From f8a8952793561c9c6ddcd2751f343ee5fc8c3a4c Mon Sep 17 00:00:00 2001
From: Shu Ding
Date: Fri, 11 Mar 2022 10:15:42 +0100
Subject: [PATCH 1/6] remove the special _document file
---
packages/next/build/entries.ts | 6 +----
packages/next/build/index.ts | 1 -
packages/next/pages/_document-concurrent.tsx | 16 ------------
packages/next/pages/_document.tsx | 4 +++
packages/next/server/dev/hot-reloader.ts | 1 -
packages/next/server/render.tsx | 26 +++++++++++++++-----
6 files changed, 25 insertions(+), 29 deletions(-)
delete mode 100644 packages/next/pages/_document-concurrent.tsx
diff --git a/packages/next/build/entries.ts b/packages/next/build/entries.ts
index 3d0047efc9b..1ac79e357ed 100644
--- a/packages/next/build/entries.ts
+++ b/packages/next/build/entries.ts
@@ -39,11 +39,9 @@ export function createPagesMapping(
{
isDev,
hasServerComponents,
- globalRuntime,
}: {
isDev: boolean
hasServerComponents: boolean
- globalRuntime?: 'nodejs' | 'edge'
}
): PagesMapping {
const previousPages: PagesMapping = {}
@@ -83,7 +81,6 @@ export function createPagesMapping(
// we alias these in development and allow webpack to
// allow falling back to the correct source file so
// that HMR can work properly when a file is added/removed
- const documentPage = `_document${globalRuntime ? '-concurrent' : ''}`
if (isDev) {
pages['/_app'] = `${PAGES_DIR_ALIAS}/_app`
pages['/_error'] = `${PAGES_DIR_ALIAS}/_error`
@@ -91,8 +88,7 @@ export function createPagesMapping(
} else {
pages['/_app'] = pages['/_app'] || 'next/dist/pages/_app'
pages['/_error'] = pages['/_error'] || 'next/dist/pages/_error'
- pages['/_document'] =
- pages['/_document'] || `next/dist/pages/${documentPage}`
+ pages['/_document'] = pages['/_document'] || `next/dist/pages/_document`
}
return pages
}
diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts
index 25cf163cb6e..b0952a2b276 100644
--- a/packages/next/build/index.ts
+++ b/packages/next/build/index.ts
@@ -298,7 +298,6 @@ export default async function build(
createPagesMapping(pagePaths, config.pageExtensions, {
isDev: false,
hasServerComponents,
- globalRuntime: runtime,
})
)
diff --git a/packages/next/pages/_document-concurrent.tsx b/packages/next/pages/_document-concurrent.tsx
deleted file mode 100644
index 8275efd253f..00000000000
--- a/packages/next/pages/_document-concurrent.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-// Default Document for streaming features
-
-import React from 'react'
-import { Html, Head, Main, NextScript } from './_document'
-
-export default function Document() {
- return (
-
-
-
-
-
-
-
- )
-}
diff --git a/packages/next/pages/_document.tsx b/packages/next/pages/_document.tsx
index 309ae6321dc..e4686083e16 100644
--- a/packages/next/pages/_document.tsx
+++ b/packages/next/pages/_document.tsx
@@ -184,6 +184,10 @@ export default class Document extends Component {
}
}
+// Add a speical property to the built-in `Document` component so later we can
+// identify if a user customized `Document` is used or not.
+;(Document as any).__next_internal_document = true
+
export function Html(
props: React.DetailedHTMLProps<
React.HtmlHTMLAttributes,
diff --git a/packages/next/server/dev/hot-reloader.ts b/packages/next/server/dev/hot-reloader.ts
index d5e56dbf4f7..bcd58454ab5 100644
--- a/packages/next/server/dev/hot-reloader.ts
+++ b/packages/next/server/dev/hot-reloader.ts
@@ -321,7 +321,6 @@ export default class HotReloader {
this.config.pageExtensions,
{
isDev: true,
- globalRuntime: this.runtime,
hasServerComponents: this.hasServerComponents,
}
)
diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx
index 679fcde4f62..120831426a4 100644
--- a/packages/next/server/render.tsx
+++ b/packages/next/server/render.tsx
@@ -431,7 +431,6 @@ export async function renderToHTML(
dev = false,
ampPath = '',
App,
- Document,
pageConfig = {},
buildManifest,
fontManifest,
@@ -457,6 +456,7 @@ export async function renderToHTML(
const hasConcurrentFeatures = !!runtime
+ let Document = renderOpts.Document
const OriginalComponent = renderOpts.Component
// We don't need to opt-into the flight inlining logic if the page isn't a RSC.
@@ -1234,14 +1234,28 @@ export async function renderToHTML(
*/
const generateStaticHTML = supportsDynamicHTML !== true
const renderDocument = async () => {
+ // For `Document`, there are two cases that we don't support:
+ // 1. Using `Document.getInitialProps` in the Edge runtime.
+ // 2. Using the class component `Document` with concurrent features.
+
+ const isBuiltinDocument = !!(Document as any).__next_internal_document
+
if (runtime === 'edge' && Document.getInitialProps) {
- // In the Edge runtime, Document.getInitialProps isn't supported.
- throw new Error(
- '`getInitialProps` in Document component is not supported with the Edge Runtime.'
- )
+ // In the Edge runtime, `Document.getInitialProps` isn't supported.
+ // We throw an error here if it's customized.
+ if (!isBuiltinDocument) {
+ throw new Error(
+ '`getInitialProps` in Document component is not supported with the Edge Runtime.'
+ )
+ }
+ }
+
+ // We make it a function component to enable streaming.
+ if (hasConcurrentFeatures && isBuiltinDocument) {
+ Document = (Document as any).render
}
- if (!runtime && Document.getInitialProps) {
+ if (!hasConcurrentFeatures && Document.getInitialProps) {
const renderPage: RenderPage = (
options: ComponentsEnhancer = {}
): RenderPageResult | Promise => {
From 506d99c504c06be75f78ecf7b9e23b1c2cec6282 Mon Sep 17 00:00:00 2001
From: Shu Ding
Date: Fri, 11 Mar 2022 14:59:46 +0100
Subject: [PATCH 2/6] bug fix
---
packages/next/build/webpack-config.ts | 4 +---
packages/next/pages/_document.tsx | 2 +-
packages/next/server/base-server.ts | 6 +++++-
packages/next/server/dev/next-dev-server.ts | 4 +---
packages/next/server/load-components.ts | 10 ++--------
5 files changed, 10 insertions(+), 16 deletions(-)
diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts
index 813dbfbdae5..300857be7bd 100644
--- a/packages/next/build/webpack-config.ts
+++ b/packages/next/build/webpack-config.ts
@@ -558,9 +558,7 @@ export default async function getBaseWebpackConfig(
prev.push(path.join(pagesDir, `_document.${ext}`))
return prev
}, [] as string[]),
- `next/dist/pages/_document${
- hasConcurrentFeatures ? '-concurrent' : ''
- }.js`,
+ `next/dist/pages/_document.js`,
]
}
diff --git a/packages/next/pages/_document.tsx b/packages/next/pages/_document.tsx
index e4686083e16..fd0dcae93b9 100644
--- a/packages/next/pages/_document.tsx
+++ b/packages/next/pages/_document.tsx
@@ -171,7 +171,7 @@ export default class Document extends Component {
return ctx.defaultGetInitialProps(ctx)
}
- render() {
+ static render() {
return (
diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts
index 2168e8d163d..01323e9abae 100644
--- a/packages/next/server/base-server.ts
+++ b/packages/next/server/base-server.ts
@@ -1176,6 +1176,10 @@ export default abstract class Server {
if (opts.supportsDynamicHTML === true) {
const isBotRequest = isBot(req.headers['user-agent'] || '')
+ const isSupportedDocument =
+ (components.Document as any).__next_internal_document ||
+ typeof components.Document?.getInitialProps !== 'function'
+
// 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 =
@@ -1183,7 +1187,7 @@ export default abstract class Server {
!isLikeServerless &&
!isBotRequest &&
!query.amp &&
- typeof components.Document?.getInitialProps !== 'function'
+ isSupportedDocument
}
const defaultLocale = isSSG
diff --git a/packages/next/server/dev/next-dev-server.ts b/packages/next/server/dev/next-dev-server.ts
index 66ad197086a..15c58725143 100644
--- a/packages/next/server/dev/next-dev-server.ts
+++ b/packages/next/server/dev/next-dev-server.ts
@@ -949,9 +949,7 @@ export default class DevServer extends Server {
// Build the error page to ensure the fallback is built too.
// TODO: See if this can be moved into hotReloader or removed.
await this.hotReloader!.ensurePage('/_error')
- return await loadDefaultErrorComponents(this.distDir, {
- hasConcurrentFeatures: !!this.renderOpts.runtime,
- })
+ return await loadDefaultErrorComponents(this.distDir)
}
protected setImmutableAssetCacheControl(res: BaseNextResponse): void {
diff --git a/packages/next/server/load-components.ts b/packages/next/server/load-components.ts
index 8ccafc60a75..ae247d9ea66 100644
--- a/packages/next/server/load-components.ts
+++ b/packages/next/server/load-components.ts
@@ -39,14 +39,8 @@ export type LoadComponentsReturnType = {
AppMod: any
}
-export async function loadDefaultErrorComponents(
- distDir: string,
- { hasConcurrentFeatures }: { hasConcurrentFeatures: boolean }
-) {
- const Document = interopDefault(
- require(`next/dist/pages/_document` +
- (hasConcurrentFeatures ? '-concurrent' : ''))
- )
+export async function loadDefaultErrorComponents(distDir: string) {
+ const Document = interopDefault(require('next/dist/pages/_document'))
const AppMod = require('next/dist/pages/_app')
const App = interopDefault(AppMod)
const ComponentMod = require('next/dist/pages/_error')
From eb6f002989a9dc56496fd0cac46ac04da8dda3fd Mon Sep 17 00:00:00 2001
From: Shu Ding
Date: Fri, 11 Mar 2022 15:25:50 +0100
Subject: [PATCH 3/6] fix revert making instance method static
---
packages/next/pages/_document.tsx | 12 ++++++++++--
packages/next/server/base-server.ts | 2 +-
packages/next/server/render.tsx | 10 ++++++----
3 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/packages/next/pages/_document.tsx b/packages/next/pages/_document.tsx
index fd0dcae93b9..d9b1c840f67 100644
--- a/packages/next/pages/_document.tsx
+++ b/packages/next/pages/_document.tsx
@@ -171,7 +171,7 @@ export default class Document extends Component {
return ctx.defaultGetInitialProps(ctx)
}
- static render() {
+ render() {
return (
@@ -186,7 +186,15 @@ export default class Document
extends Component {
// Add a speical property to the built-in `Document` component so later we can
// identify if a user customized `Document` is used or not.
-;(Document as any).__next_internal_document = true
+;(Document as any).__next_internal_document = () => (
+
+
+
+
+
+
+
+)
export function Html(
props: React.DetailedHTMLProps<
diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts
index 01323e9abae..757be04adaf 100644
--- a/packages/next/server/base-server.ts
+++ b/packages/next/server/base-server.ts
@@ -1177,7 +1177,7 @@ export default abstract class Server {
if (opts.supportsDynamicHTML === true) {
const isBotRequest = isBot(req.headers['user-agent'] || '')
const isSupportedDocument =
- (components.Document as any).__next_internal_document ||
+ !!(components.Document as any).__next_internal_document ||
typeof components.Document?.getInitialProps !== 'function'
// Disable dynamic HTML in cases that we know it won't be generated,
diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx
index 120831426a4..8b9eae2fbb6 100644
--- a/packages/next/server/render.tsx
+++ b/packages/next/server/render.tsx
@@ -1238,12 +1238,14 @@ export async function renderToHTML(
// 1. Using `Document.getInitialProps` in the Edge runtime.
// 2. Using the class component `Document` with concurrent features.
- const isBuiltinDocument = !!(Document as any).__next_internal_document
+ const builtinDocument = (Document as any).__next_internal_document as
+ | typeof Document
+ | undefined
if (runtime === 'edge' && Document.getInitialProps) {
// In the Edge runtime, `Document.getInitialProps` isn't supported.
// We throw an error here if it's customized.
- if (!isBuiltinDocument) {
+ if (!builtinDocument) {
throw new Error(
'`getInitialProps` in Document component is not supported with the Edge Runtime.'
)
@@ -1251,8 +1253,8 @@ export async function renderToHTML(
}
// We make it a function component to enable streaming.
- if (hasConcurrentFeatures && isBuiltinDocument) {
- Document = (Document as any).render
+ if (hasConcurrentFeatures && builtinDocument) {
+ Document = builtinDocument
}
if (!hasConcurrentFeatures && Document.getInitialProps) {
From 4465c530a820bd044779143da9cbb1cd757d8a96 Mon Sep 17 00:00:00 2001
From: Shu Ding
Date: Fri, 11 Mar 2022 15:46:29 +0100
Subject: [PATCH 4/6] fix test; refine document to have name
---
packages/next/pages/_document.tsx | 21 ++++++++++++---------
packages/next/server/base-server.ts | 2 +-
2 files changed, 13 insertions(+), 10 deletions(-)
diff --git a/packages/next/pages/_document.tsx b/packages/next/pages/_document.tsx
index d9b1c840f67..43ae26369f8 100644
--- a/packages/next/pages/_document.tsx
+++ b/packages/next/pages/_document.tsx
@@ -186,15 +186,18 @@ export default class Document extends Component {
// Add a speical property to the built-in `Document` component so later we can
// identify if a user customized `Document` is used or not.
-;(Document as any).__next_internal_document = () => (
-
-
-
-
-
-
-
-)
+;(Document as any).__next_internal_document =
+ function InternalFunctionDocument() {
+ return (
+
+
+
+
+
+
+
+ )
+ }
export function Html(
props: React.DetailedHTMLProps<
diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts
index 757be04adaf..1146f3e58c0 100644
--- a/packages/next/server/base-server.ts
+++ b/packages/next/server/base-server.ts
@@ -1177,7 +1177,7 @@ export default abstract class Server {
if (opts.supportsDynamicHTML === true) {
const isBotRequest = isBot(req.headers['user-agent'] || '')
const isSupportedDocument =
- !!(components.Document as any).__next_internal_document ||
+ (components.Document as any)?.__next_internal_document ||
typeof components.Document?.getInitialProps !== 'function'
// Disable dynamic HTML in cases that we know it won't be generated,
From 9c7716493b7550dc62d5e90b0277f5b5c461212b Mon Sep 17 00:00:00 2001
From: Shu Ding
Date: Fri, 11 Mar 2022 18:15:33 +0100
Subject: [PATCH 5/6] fix condition
---
packages/next/server/base-server.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts
index 1146f3e58c0..92f555cabff 100644
--- a/packages/next/server/base-server.ts
+++ b/packages/next/server/base-server.ts
@@ -1177,7 +1177,7 @@ export default abstract class Server {
if (opts.supportsDynamicHTML === true) {
const isBotRequest = isBot(req.headers['user-agent'] || '')
const isSupportedDocument =
- (components.Document as any)?.__next_internal_document ||
+ !!(components.Document as any)?.__next_internal_document ||
typeof components.Document?.getInitialProps !== 'function'
// Disable dynamic HTML in cases that we know it won't be generated,
From 54da6d0ef6fbfb2a260c884ccdcfc9f37bfc39a4 Mon Sep 17 00:00:00 2001
From: Shu Ding
Date: Fri, 11 Mar 2022 19:36:52 +0100
Subject: [PATCH 6/6] fix dynamic html condition
---
packages/next/server/base-server.ts | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts
index 92f555cabff..56f0dedf8a1 100644
--- a/packages/next/server/base-server.ts
+++ b/packages/next/server/base-server.ts
@@ -1177,8 +1177,11 @@ export default abstract class Server {
if (opts.supportsDynamicHTML === true) {
const isBotRequest = isBot(req.headers['user-agent'] || '')
const isSupportedDocument =
- !!(components.Document as any)?.__next_internal_document ||
- typeof components.Document?.getInitialProps !== 'function'
+ typeof components.Document?.getInitialProps !== 'function' ||
+ // When concurrent features is enabled, the built-in `Document`
+ // component also supports dynamic HTML.
+ (this.renderOpts.reactRoot &&
+ !!(components.Document as any)?.__next_internal_document)
// Disable dynamic HTML in cases that we know it won't be generated,
// so that we can continue generating a cache key when possible.