Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify static + dynamic HTML generation #28793

Merged
merged 1 commit into from
Sep 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) {
previewProps: encodedPreviewProps,
env: process.env,
basePath,
requireStaticHTML: true, // Serverless target doesn't support streaming
supportsDynamicHTML: false, // Serverless target doesn't support streaming
..._renderOpts,
}
let _nextData = false
Expand Down
4 changes: 2 additions & 2 deletions packages/next/export/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,8 @@ export default async function exportApp(
domainLocales: i18n?.domains,
trailingSlash: nextConfig.trailingSlash,
disableOptimizedLoading: nextConfig.experimental.disableOptimizedLoading,
// TODO: We should support dynamic HTML too
requireStaticHTML: true,
// Exported pages do not currently support dynamic HTML.
supportsDynamicHTML: false,
concurrentFeatures: nextConfig.experimental.concurrentFeatures,
}

Expand Down
25 changes: 15 additions & 10 deletions packages/next/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1250,13 +1250,12 @@ export default class Server {
query: ParsedUrlQuery
}
): Promise<void> {
// TODO: Determine when dynamic HTML is allowed
const requireStaticHTML = true
const ctx = {
...partialContext,
renderOpts: {
...this.renderOpts,
requireStaticHTML,
// TODO: Determine when dynamic HTML is allowed
supportsDynamicHTML: false,
},
} as const
const payload = await fn(ctx)
Expand Down Expand Up @@ -1296,17 +1295,12 @@ export default class Server {
...partialContext,
renderOpts: {
...this.renderOpts,
requireStaticHTML: true,
supportsDynamicHTML: false,
},
})
if (payload === null) {
return null
}
if (payload.body.isDynamic()) {
throw new Error(
'invariant: expected a static result. This is a bug in Next.js'
)
}
return payload.body.toUnchunkedString()
}

Expand Down Expand Up @@ -1490,6 +1484,17 @@ export default class Server {
delete query.amp
}

if (opts.supportsDynamicHTML === true) {
// Disable dynamic HTML in cases that we know it won't be generated,
// so that we can continue generating a cache key when possible.
opts.supportsDynamicHTML =
!isSSG &&
!isLikeServerless &&
!query.amp &&
!this.minimalMode &&
typeof components.Document.getInitialProps !== 'function'
}

const locale = query.__nextLocale as string
const defaultLocale = isSSG
? this.nextConfig.i18n?.defaultLocale
Expand Down Expand Up @@ -1574,7 +1579,7 @@ export default class Server {
}

let ssgCacheKey =
isPreviewMode || !isSSG || this.minimalMode
isPreviewMode || !isSSG || this.minimalMode || opts.supportsDynamicHTML
huozhi marked this conversation as resolved.
Show resolved Hide resolved
? null // Preview mode bypasses the cache
: `${locale ? `/${locale}` : ''}${
(pathname === '/' || resolvedUrlPathname === '/') && locale
Expand Down
19 changes: 16 additions & 3 deletions packages/next/server/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ export type RenderOptsPartial = {
defaultLocale?: string
domainLocales?: DomainLocale[]
disableOptimizedLoading?: boolean
requireStaticHTML?: boolean
supportsDynamicHTML?: boolean
concurrentFeatures?: boolean
customServer?: boolean
}
Expand Down Expand Up @@ -295,7 +295,7 @@ export async function renderToHTML(
previewProps,
basePath,
devOnlyCacheBusterQueryString,
requireStaticHTML,
supportsDynamicHTML,
concurrentFeatures,
} = renderOpts

Expand Down Expand Up @@ -883,7 +883,20 @@ export async function renderToHTML(
}
}

const generateStaticHTML = requireStaticHTML || inAmpMode
/**
* Rules of Static & Dynamic HTML:
*
* 1.) We must generate static HTML unless the caller explicitly opts
* in to dynamic HTML support.
*
* 2.) If dynamic HTML support is requested, we must honor that request
* or throw an error. It is the sole responsibility of the caller to
* ensure they aren't e.g. requesting dynamic HTML for an AMP page.
*
* These rules help ensure that other existing features like request caching,
* coalescing, and ISR continue working as intended.
*/
const generateStaticHTML = supportsDynamicHTML !== true
const renderToStream = (element: React.ReactElement) =>
new Promise<Observable<string>>((resolve, reject) => {
const stream = new PassThrough()
Expand Down