From e83cd279e0b1f68102fe5f0946f79a4d98633828 Mon Sep 17 00:00:00 2001 From: Gerald Monaco Date: Thu, 12 Aug 2021 15:42:53 +0000 Subject: [PATCH 1/3] Clean up DocumentContext --- packages/next/pages/_document.tsx | 48 +++------ packages/next/server/render.tsx | 108 ++++++++++--------- packages/next/shared/lib/constants.ts | 2 +- packages/next/shared/lib/document-context.ts | 8 -- packages/next/shared/lib/utils.ts | 19 ++-- 5 files changed, 85 insertions(+), 100 deletions(-) delete mode 100644 packages/next/shared/lib/document-context.ts 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..5530f75a7d88287 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, @@ -63,6 +63,7 @@ import { } from '../lib/load-custom-routes' import { DomainLocale } from './config' import { RenderResult, resultFromChunks } from './utils' +import { HtmlContext } from '../dist/server/document' function noRouter() { const message = @@ -264,54 +265,56 @@ 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, + } 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 +1158,15 @@ export async function renderToHTML( } } + 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) { - // 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) - 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' +} From e1e753ca37ed0f6ba4ce0b09f49a1a71bd3fbb90 Mon Sep 17 00:00:00 2001 From: Gerald Monaco Date: Thu, 12 Aug 2021 15:59:52 +0000 Subject: [PATCH 2/3] Fix build --- packages/next/server/render.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx index 5530f75a7d88287..0ef245149ef4619 100644 --- a/packages/next/server/render.tsx +++ b/packages/next/server/render.tsx @@ -39,6 +39,7 @@ import { DocumentInitialProps, DocumentProps, DocumentType, + HtmlContext, getDisplayName, isResSent, loadGetInitialProps, @@ -63,7 +64,6 @@ import { } from '../lib/load-custom-routes' import { DomainLocale } from './config' import { RenderResult, resultFromChunks } from './utils' -import { HtmlContext } from '../dist/server/document' function noRouter() { const message = From 663ae286d334cc71f06e3e5b88a9f0c22244b20e Mon Sep 17 00:00:00 2001 From: Gerald Monaco Date: Thu, 12 Aug 2021 16:18:30 +0000 Subject: [PATCH 3/3] Fix tests --- packages/next/server/render.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx index 0ef245149ef4619..7045073b8c0e43b 100644 --- a/packages/next/server/render.tsx +++ b/packages/next/server/render.tsx @@ -307,6 +307,8 @@ function renderDocument( scriptLoader, locale, disableOptimizedLoading, + styles: docProps.styles, + head: docProps.head, } return ( '' + @@ -1165,7 +1167,7 @@ export async function renderToHTML( docProps.html + html.substring(bodyRenderIdx + BODY_RENDER_TARGET.length) - if (inAmpMode && html) { + if (inAmpMode) { html = await optimizeAmp(html, renderOpts.ampOptimizerConfig) if (!renderOpts.ampSkipValidation && renderOpts.ampValidator) { await renderOpts.ampValidator(html, pathname)