From 9b6a63693797b622b96b21b8ba5fdda6628b9b8a Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Wed, 3 Nov 2021 19:09:44 +0100 Subject: [PATCH 1/4] conditionally import react-dom/server --- .../next/build/webpack/config/blocks/base.ts | 6 ++- packages/next/server/react-dom-server.ts | 13 +++++ packages/next/server/render.tsx | 52 +++++++++++++++---- 3 files changed, 61 insertions(+), 10 deletions(-) create mode 100644 packages/next/server/react-dom-server.ts diff --git a/packages/next/build/webpack/config/blocks/base.ts b/packages/next/build/webpack/config/blocks/base.ts index 9c8799633391f59..34ee68b412520a5 100644 --- a/packages/next/build/webpack/config/blocks/base.ts +++ b/packages/next/build/webpack/config/blocks/base.ts @@ -14,7 +14,11 @@ export const base = curry(function base( : 'client' // @ts-ignore TODO webpack 5 typings - config.target = !ctx.targetWeb ? 'node12.22' : ['web', 'es5'] + config.target = !ctx.targetWeb + ? 'node12.22' + : ctx.webServerRuntime + ? ['web', 'es6'] + : ['web', 'es5'] // https://webpack.js.org/configuration/devtool/#development if (ctx.isDevelopment) { diff --git a/packages/next/server/react-dom-server.ts b/packages/next/server/react-dom-server.ts new file mode 100644 index 000000000000000..f5b4f1c6a2b1822 --- /dev/null +++ b/packages/next/server/react-dom-server.ts @@ -0,0 +1,13 @@ +let ReactDOMServer: typeof import('react-dom/server') + +if (process.browser) { + if (process.env.NODE_ENV === 'production') { + ReactDOMServer = require('react-dom/cjs/react-dom-server.browser.production.min') + } else { + ReactDOMServer = require('react-dom/cjs/react-dom-server.browser.development') + } +} else { + ReactDOMServer = require('react-dom/server') +} + +export default ReactDOMServer diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx index 8059b75c172c0e2..cb16e01c94dfec7 100644 --- a/packages/next/server/render.tsx +++ b/packages/next/server/render.tsx @@ -2,7 +2,7 @@ import { IncomingMessage, ServerResponse } from 'http' import { ParsedUrlQuery } from 'querystring' import type { Writable as WritableType } from 'stream' import React from 'react' -import * as ReactDOMServer from 'react-dom/server' +import ReactDOMServer from './react-dom-server' import { StyleRegistry, createStyleRegistry } from 'styled-jsx' import { UnwrapPromise } from '../lib/coalesced-function' import { @@ -950,7 +950,12 @@ export async function renderToHTML( */ const generateStaticHTML = supportsDynamicHTML !== true const renderDocument = async () => { - if (Document.getInitialProps) { + if (process.browser && Document.getInitialProps) { + throw new Error( + '`getInitialProps` in Document component is not supported with `concurrentFeatures` enabled.' + ) + } + if (!process.browser && Document.getInitialProps) { const renderPage: RenderPage = ( options: ComponentsEnhancer = {} ): RenderPageResult | Promise => { @@ -1120,13 +1125,42 @@ export async function renderToHTML( styles: documentResult.styles, useMaybeDeferContent, } - const documentHTML = ReactDOMServer.renderToStaticMarkup( - - - {documentResult.documentElement(htmlProps)} - - - ) + + let documentHTML: string + if (process.browser) { + // There is no `renderToStaticMarkup` exposed in the web environment. + let result = '' + const readable = (ReactDOMServer as any).renderToReadableStream( + + + {documentResult.documentElement(htmlProps)} + + , + { + onError: (err: any) => { + throw err + }, + } + ) + const reader = readable.getReader() + const decoder = new TextDecoder() + while (true) { + const { done, value } = await reader.read() + if (done) { + break + } + result += typeof value === 'string' ? value : decoder.decode(value) + } + documentHTML = result + } else { + documentHTML = ReactDOMServer.renderToStaticMarkup( + + + {documentResult.documentElement(htmlProps)} + + + ) + } if (process.env.NODE_ENV !== 'production') { const nonRenderedComponents = [] From 44569339086858050edd1081f9117356e6b44e04 Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Fri, 5 Nov 2021 16:21:49 +0100 Subject: [PATCH 2/4] refactor --- packages/next/server/render.tsx | 36 +++++++++++++++------------------ 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx index cb16e01c94dfec7..bb26aed2b396788 100644 --- a/packages/next/server/render.tsx +++ b/packages/next/server/render.tsx @@ -1126,22 +1126,24 @@ export async function renderToHTML( useMaybeDeferContent, } + const document = ( + + + {documentResult.documentElement(htmlProps)} + + + ) + let documentHTML: string if (process.browser) { - // There is no `renderToStaticMarkup` exposed in the web environment. + // There is no `renderToStaticMarkup` exposed in the web environment, use + // blocking `renderToReadableStream` to get the similar result. let result = '' - const readable = (ReactDOMServer as any).renderToReadableStream( - - - {documentResult.documentElement(htmlProps)} - - , - { - onError: (err: any) => { - throw err - }, - } - ) + const readable = (ReactDOMServer as any).renderToReadableStream(document, { + onError: (err: any) => { + throw err + }, + }) const reader = readable.getReader() const decoder = new TextDecoder() while (true) { @@ -1153,13 +1155,7 @@ export async function renderToHTML( } documentHTML = result } else { - documentHTML = ReactDOMServer.renderToStaticMarkup( - - - {documentResult.documentElement(htmlProps)} - - - ) + documentHTML = ReactDOMServer.renderToStaticMarkup(document) } if (process.env.NODE_ENV !== 'production') { From 3e146d978e70e1f5d1434add4080f840c3f4620f Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Fri, 5 Nov 2021 18:29:17 +0100 Subject: [PATCH 3/4] use webpack alias --- packages/next/build/webpack-config.ts | 8 ++++++++ packages/next/server/react-dom-server.ts | 13 ------------- packages/next/server/render.tsx | 2 +- 3 files changed, 9 insertions(+), 14 deletions(-) delete mode 100644 packages/next/server/react-dom-server.ts diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index eab85535f3556a3..71174550d9c0f25 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -676,6 +676,14 @@ export default async function getBaseWebpackConfig( false, } : {}), + + ...(webServerRuntime + ? { + 'react-dom/server': dev + ? 'react-dom/cjs/react-dom-server.browser.development' + : 'react-dom/cjs/react-dom-server.browser.production.min', + } + : {}), }, ...(targetWeb ? { diff --git a/packages/next/server/react-dom-server.ts b/packages/next/server/react-dom-server.ts deleted file mode 100644 index f5b4f1c6a2b1822..000000000000000 --- a/packages/next/server/react-dom-server.ts +++ /dev/null @@ -1,13 +0,0 @@ -let ReactDOMServer: typeof import('react-dom/server') - -if (process.browser) { - if (process.env.NODE_ENV === 'production') { - ReactDOMServer = require('react-dom/cjs/react-dom-server.browser.production.min') - } else { - ReactDOMServer = require('react-dom/cjs/react-dom-server.browser.development') - } -} else { - ReactDOMServer = require('react-dom/server') -} - -export default ReactDOMServer diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx index bb26aed2b396788..8ffdc2cabf991d3 100644 --- a/packages/next/server/render.tsx +++ b/packages/next/server/render.tsx @@ -2,7 +2,7 @@ import { IncomingMessage, ServerResponse } from 'http' import { ParsedUrlQuery } from 'querystring' import type { Writable as WritableType } from 'stream' import React from 'react' -import ReactDOMServer from './react-dom-server' +import ReactDOMServer from 'react-dom/server' import { StyleRegistry, createStyleRegistry } from 'styled-jsx' import { UnwrapPromise } from '../lib/coalesced-function' import { From 92f00abd66f0a1606eca725f0b62debe03e50ebb Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Fri, 5 Nov 2021 21:47:03 +0100 Subject: [PATCH 4/4] fix lint error --- packages/next/server/render.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx index 8ffdc2cabf991d3..53fa578287d73ab 100644 --- a/packages/next/server/render.tsx +++ b/packages/next/server/render.tsx @@ -1140,8 +1140,8 @@ export async function renderToHTML( // blocking `renderToReadableStream` to get the similar result. let result = '' const readable = (ReactDOMServer as any).renderToReadableStream(document, { - onError: (err: any) => { - throw err + onError: (e: any) => { + throw e }, }) const reader = readable.getReader()