diff --git a/packages/next/build/entries.ts b/packages/next/build/entries.ts index 560f7da3fdaf57..f188ca2198c985 100644 --- a/packages/next/build/entries.ts +++ b/packages/next/build/entries.ts @@ -141,6 +141,7 @@ export function createEntrypoints( 'base64' ), i18n: config.i18n ? JSON.stringify(config.i18n) : '', + reactRoot: config.experimental.reactRoot ? 'true' : '', } Object.keys(pages).forEach((page) => { diff --git a/packages/next/build/webpack/loaders/next-serverless-loader/index.ts b/packages/next/build/webpack/loaders/next-serverless-loader/index.ts index fba18ce964f7a2..e9f8630262fc55 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader/index.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader/index.ts @@ -31,6 +31,7 @@ export type ServerlessLoaderQuery = { previewProps: string loadedEnvFiles: string i18n: string + reactRoot: string } const nextServerlessLoader: webpack.loader.Loader = function () { @@ -52,6 +53,7 @@ const nextServerlessLoader: webpack.loader.Loader = function () { previewProps, loadedEnvFiles, i18n, + reactRoot, }: ServerlessLoaderQuery = typeof this.query === 'string' ? parse(this.query.substr(1)) : this.query @@ -193,6 +195,7 @@ const nextServerlessLoader: webpack.loader.Loader = function () { canonicalBase: "${canonicalBase}", generateEtags: ${generateEtags || 'false'}, poweredByHeader: ${poweredByHeader || 'false'}, + reactRoot: ${reactRoot || 'false'}, runtimeConfig, buildManifest, diff --git a/packages/next/export/index.ts b/packages/next/export/index.ts index e7d7d758a26f5b..b1b63918307ff4 100644 --- a/packages/next/export/index.ts +++ b/packages/next/export/index.ts @@ -386,6 +386,7 @@ export default async function exportApp( optimizeCss: nextConfig.experimental.optimizeCss, optimizeFonts: nextConfig.optimizeFonts, optimizeImages: nextConfig.experimental.optimizeImages, + reactRoot: nextConfig.experimental.reactRoot || false, } const { serverRuntimeConfig, publicRuntimeConfig } = nextConfig diff --git a/packages/next/server/base-server.ts b/packages/next/server/base-server.ts index 2541d3faec0211..4f7fc2b510ca5b 100644 --- a/packages/next/server/base-server.ts +++ b/packages/next/server/base-server.ts @@ -163,6 +163,7 @@ export default abstract class Server { serverComponentManifest?: any renderServerComponentData?: boolean serverComponentProps?: any + reactRoot: boolean } private incrementalCache: IncrementalCache private responseCache: ResponseCache @@ -321,6 +322,7 @@ export default abstract class Server { crossOrigin: this.nextConfig.crossOrigin ? this.nextConfig.crossOrigin : undefined, + reactRoot: this.nextConfig.experimental.reactRoot === true, } // Only the `publicRuntimeConfig` key is exposed to the client side diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx index fcd4db24e4df11..bc71c40a598561 100644 --- a/packages/next/server/render.tsx +++ b/packages/next/server/render.tsx @@ -232,6 +232,7 @@ export type RenderOptsPartial = { serverComponents?: boolean customServer?: boolean crossOrigin?: string + reactRoot: boolean } export type RenderOpts = LoadComponentsReturnType & RenderOptsPartial @@ -456,6 +457,7 @@ export async function renderToHTML( basePath, devOnlyCacheBusterQueryString, supportsDynamicHTML, + reactRoot, runtime, } = renderOpts @@ -1265,7 +1267,7 @@ export async function renderToHTML( ) } - if (hasConcurrentFeatures) { + if (reactRoot) { bodyResult = async (suffix: string) => { // this must be called inside bodyResult so appWrappers is // up to date when getWrappedApp is called @@ -1277,7 +1279,7 @@ export async function renderToHTML( suffix, serverComponentsInlinedTransformStream?.readable ?? streamFromArray([]), - generateStaticHTML + generateStaticHTML || !hasConcurrentFeatures ) } } else {