diff --git a/packages/next/pages/_document.tsx b/packages/next/pages/_document.tsx
index e11b7386a9acfcb..7217ce72f94f251 100644
--- a/packages/next/pages/_document.tsx
+++ b/packages/next/pages/_document.tsx
@@ -1,14 +1,15 @@
import React, { Component, ReactElement, ReactNode, useContext } from 'react'
import flush from 'styled-jsx/server'
import {
- AMP_RENDER_TARGET,
+ BODY_RENDER_TARGET,
OPTIMIZED_FONT_PROVIDERS,
} from '../shared/lib/constants'
-import { DocumentContext as DocumentComponentContext } from '../shared/lib/document-context'
import {
DocumentContext,
DocumentInitialProps,
DocumentProps,
+ HtmlContext,
+ HtmlProps,
} from '../shared/lib/utils'
import { BuildManifest, getPageFiles } from '../server/get-page-files'
import { cleanAmpPath } from '../server/utils'
@@ -45,7 +46,7 @@ function getDocumentFiles(
}
}
-function getPolyfillScripts(context: DocumentProps, props: OriginProps) {
+function getPolyfillScripts(context: HtmlProps, props: OriginProps) {
// polyfills.js has to be rendered as nomodule without async
// It also has to be the first script to load
const {
@@ -71,7 +72,7 @@ function getPolyfillScripts(context: DocumentProps, props: OriginProps) {
))
}
-function getPreNextScripts(context: DocumentProps, props: OriginProps) {
+function getPreNextScripts(context: HtmlProps, props: OriginProps) {
const { scriptLoader, disableOptimizedLoading } = context
return (scriptLoader.beforeInteractive || []).map(
@@ -91,7 +92,7 @@ function getPreNextScripts(context: DocumentProps, props: OriginProps) {
}
function getDynamicChunks(
- context: DocumentProps,
+ context: HtmlProps,
props: OriginProps,
files: DocumentFiles
) {
@@ -122,7 +123,7 @@ function getDynamicChunks(
}
function getScripts(
- context: DocumentProps,
+ context: HtmlProps,
props: OriginProps,
files: DocumentFiles
) {
@@ -176,17 +177,6 @@ export default class Document
extends Component {
return { html, head, styles }
}
- static renderDocument(
- DocumentComponent: new () => Document,
- props: DocumentProps & Y
- ): React.ReactElement {
- return (
-
-
-
- )
- }
-
render() {
return (
@@ -206,9 +196,7 @@ export function Html(
HTMLHtmlElement
>
) {
- const { inAmpMode, docComponentsRendered, locale } = useContext(
- DocumentComponentContext
- )
+ const { inAmpMode, docComponentsRendered, locale } = useContext(HtmlContext)
docComponentsRendered.Html = true
@@ -231,9 +219,9 @@ export class Head extends Component<
HTMLHeadElement
>
> {
- static contextType = DocumentComponentContext
+ static contextType = HtmlContext
- context!: React.ContextType
+ context!: React.ContextType
getCssLinks(files: DocumentFiles): JSX.Element[] | null {
const {
@@ -738,20 +726,18 @@ export class Head extends Component<
}
export function Main() {
- const { inAmpMode, html, docComponentsRendered } = useContext(
- DocumentComponentContext
- )
+ const { inAmpMode, docComponentsRendered } = useContext(HtmlContext)
docComponentsRendered.Main = true
- if (inAmpMode) return <>{AMP_RENDER_TARGET}>
- return
+ if (inAmpMode) return <>{BODY_RENDER_TARGET}>
+ return {BODY_RENDER_TARGET}
}
export class NextScript extends Component {
- static contextType = DocumentComponentContext
+ static contextType = HtmlContext
- context!: React.ContextType
+ context!: React.ContextType
// Source: https://gist.github.com/samthor/64b114e4a4f539915a95b91ffd340acc
static safariNomoduleFix =
@@ -773,8 +759,8 @@ export class NextScript extends Component {
return getPolyfillScripts(this.context, this.props)
}
- static getInlineScriptSource(documentProps: Readonly): string {
- const { __NEXT_DATA__ } = documentProps
+ static getInlineScriptSource(context: Readonly): string {
+ const { __NEXT_DATA__ } = context
try {
const data = JSON.stringify(__NEXT_DATA__)
return htmlEscapeJsonString(data)
diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx
index fdc515ed7321ff4..7045073b8c0e43b 100644
--- a/packages/next/server/render.tsx
+++ b/packages/next/server/render.tsx
@@ -20,7 +20,7 @@ import { GetServerSideProps, GetStaticProps, PreviewData } from '../types'
import { isInAmpMode } from '../shared/lib/amp'
import { AmpStateContext } from '../shared/lib/amp-context'
import {
- AMP_RENDER_TARGET,
+ BODY_RENDER_TARGET,
SERVER_PROPS_ID,
STATIC_PROPS_ID,
STATIC_STATUS_PAGES,
@@ -39,6 +39,7 @@ import {
DocumentInitialProps,
DocumentProps,
DocumentType,
+ HtmlContext,
getDisplayName,
isResSent,
loadGetInitialProps,
@@ -264,54 +265,58 @@ function renderDocument(
autoExport?: boolean
}
): string {
+ const htmlProps = {
+ __NEXT_DATA__: {
+ props, // The result of getInitialProps
+ page: pathname, // The rendered page
+ query, // querystring parsed / passed by the user
+ buildId, // buildId is used to facilitate caching of page bundles, we send it to the client so that pageloader knows where to load bundles
+ assetPrefix: assetPrefix === '' ? undefined : assetPrefix, // send assetPrefix to the client side when configured, otherwise don't sent in the resulting HTML
+ runtimeConfig, // runtimeConfig if provided, otherwise don't sent in the resulting HTML
+ nextExport, // If this is a page exported by `next export`
+ autoExport, // If this is an auto exported page
+ isFallback,
+ dynamicIds:
+ dynamicImportsIds.length === 0 ? undefined : dynamicImportsIds,
+ err: err ? serializeError(dev, err) : undefined, // Error if one happened, otherwise don't sent in the resulting HTML
+ gsp, // whether the page is getStaticProps
+ gssp, // whether the page is getServerSideProps
+ customServer, // whether the user is using a custom server
+ gip, // whether the page has getInitialProps
+ appGip, // whether the _app has getInitialProps
+ locale,
+ locales,
+ defaultLocale,
+ domainLocales,
+ isPreview,
+ },
+ buildManifest,
+ docComponentsRendered,
+ dangerousAsPath,
+ canonicalBase,
+ ampPath,
+ inAmpMode,
+ isDevelopment: !!dev,
+ hybridAmp,
+ dynamicImports,
+ assetPrefix,
+ headTags,
+ unstable_runtimeJS,
+ unstable_JsPreload,
+ devOnlyCacheBusterQueryString,
+ scriptLoader,
+ locale,
+ disableOptimizedLoading,
+ styles: docProps.styles,
+ head: docProps.head,
+ }
return (
'' +
ReactDOMServer.renderToStaticMarkup(
- {Document.renderDocument(Document, {
- __NEXT_DATA__: {
- props, // The result of getInitialProps
- page: pathname, // The rendered page
- query, // querystring parsed / passed by the user
- buildId, // buildId is used to facilitate caching of page bundles, we send it to the client so that pageloader knows where to load bundles
- assetPrefix: assetPrefix === '' ? undefined : assetPrefix, // send assetPrefix to the client side when configured, otherwise don't sent in the resulting HTML
- runtimeConfig, // runtimeConfig if provided, otherwise don't sent in the resulting HTML
- nextExport, // If this is a page exported by `next export`
- autoExport, // If this is an auto exported page
- isFallback,
- dynamicIds:
- dynamicImportsIds.length === 0 ? undefined : dynamicImportsIds,
- err: err ? serializeError(dev, err) : undefined, // Error if one happened, otherwise don't sent in the resulting HTML
- gsp, // whether the page is getStaticProps
- gssp, // whether the page is getServerSideProps
- customServer, // whether the user is using a custom server
- gip, // whether the page has getInitialProps
- appGip, // whether the _app has getInitialProps
- locale,
- locales,
- defaultLocale,
- domainLocales,
- isPreview,
- },
- buildManifest,
- docComponentsRendered,
- dangerousAsPath,
- canonicalBase,
- ampPath,
- inAmpMode,
- isDevelopment: !!dev,
- hybridAmp,
- dynamicImports,
- assetPrefix,
- headTags,
- unstable_runtimeJS,
- unstable_JsPreload,
- devOnlyCacheBusterQueryString,
- scriptLoader,
- locale,
- disableOptimizedLoading,
- ...docProps,
- })}
+
+
+
)
)
@@ -1155,16 +1160,15 @@ export async function renderToHTML(
}
}
- if (inAmpMode && html) {
- // inject HTML to AMP_RENDER_TARGET to allow rendering
- // directly to body in AMP mode
- const ampRenderIndex = html.indexOf(AMP_RENDER_TARGET)
- html =
- html.substring(0, ampRenderIndex) +
- `${docProps.html}` +
- html.substring(ampRenderIndex + AMP_RENDER_TARGET.length)
- html = await optimizeAmp(html, renderOpts.ampOptimizerConfig)
+ const bodyRenderIdx = html.indexOf(BODY_RENDER_TARGET)
+ html =
+ html.substring(0, bodyRenderIdx) +
+ (inAmpMode ? '' : '') +
+ docProps.html +
+ html.substring(bodyRenderIdx + BODY_RENDER_TARGET.length)
+ if (inAmpMode) {
+ html = await optimizeAmp(html, renderOpts.ampOptimizerConfig)
if (!renderOpts.ampSkipValidation && renderOpts.ampValidator) {
await renderOpts.ampValidator(html, pathname)
}
diff --git a/packages/next/shared/lib/constants.ts b/packages/next/shared/lib/constants.ts
index 8ea2a7d271dd995..3b8e639a378e8ee 100644
--- a/packages/next/shared/lib/constants.ts
+++ b/packages/next/shared/lib/constants.ts
@@ -21,7 +21,7 @@ export const BLOCKED_PAGES = ['/_document', '/_app', '/_error']
export const CLIENT_PUBLIC_FILES_PATH = 'public'
export const CLIENT_STATIC_FILES_PATH = 'static'
export const CLIENT_STATIC_FILES_RUNTIME = 'runtime'
-export const AMP_RENDER_TARGET = '__NEXT_AMP_RENDER_TARGET__'
+export const BODY_RENDER_TARGET = '__NEXT_BODY_RENDER_TARGET__'
export const STRING_LITERAL_DROP_BUNDLE = '__NEXT_DROP_CLIENT_FILE__'
// static/runtime/main.js
export const CLIENT_STATIC_FILES_RUNTIME_MAIN = `main`
diff --git a/packages/next/shared/lib/document-context.ts b/packages/next/shared/lib/document-context.ts
deleted file mode 100644
index d3601e7a5b280a3..000000000000000
--- a/packages/next/shared/lib/document-context.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import React from 'react'
-import { DocumentProps } from './utils'
-
-export const DocumentContext = React.createContext(null as any)
-
-if (process.env.NODE_ENV !== 'production') {
- DocumentContext.displayName = 'DocumentContext'
-}
diff --git a/packages/next/shared/lib/utils.ts b/packages/next/shared/lib/utils.ts
index fdc405dec1cca9d..8413e120da896d6 100644
--- a/packages/next/shared/lib/utils.ts
+++ b/packages/next/shared/lib/utils.ts
@@ -8,6 +8,7 @@ import type { NextRouter } from './router/router'
import type { ParsedUrlQuery } from 'querystring'
import type { PreviewData } from 'next/types'
import type { UrlObject } from 'url'
+import { createContext } from 'react'
export type NextComponentType<
C extends BaseContext = NextPageContext,
@@ -26,12 +27,7 @@ export type DocumentType = NextComponentType<
DocumentContext,
DocumentInitialProps,
DocumentProps
-> & {
- renderDocument(
- Document: DocumentType,
- props: DocumentProps
- ): React.ReactElement
-}
+>
export type AppType = NextComponentType<
AppContextType,
@@ -188,7 +184,9 @@ export type DocumentInitialProps = RenderPageResult & {
styles?: React.ReactElement[] | React.ReactFragment
}
-export type DocumentProps = DocumentInitialProps & {
+export type DocumentProps = DocumentInitialProps & HtmlProps
+
+export type HtmlProps = {
__NEXT_DATA__: NEXT_DATA
dangerousAsPath: string
docComponentsRendered: {
@@ -212,6 +210,8 @@ export type DocumentProps = DocumentInitialProps & {
scriptLoader: { afterInteractive?: string[]; beforeInteractive?: any[] }
locale?: string
disableOptimizedLoading?: boolean
+ styles?: React.ReactElement[] | React.ReactFragment
+ head?: Array
}
/**
@@ -432,3 +432,8 @@ export const ST =
typeof performance.measure === 'function'
export class DecodeError extends Error {}
+
+export const HtmlContext = createContext(null as any)
+if (process.env.NODE_ENV !== 'production') {
+ HtmlContext.displayName = 'HtmlContext'
+}