diff --git a/packages/next/build/entries.ts b/packages/next/build/entries.ts index 133b2f49ddae1..560f7da3fdaf5 100644 --- a/packages/next/build/entries.ts +++ b/packages/next/build/entries.ts @@ -37,11 +37,11 @@ export function createPagesMapping( { isDev, hasServerComponents, - hasConcurrentFeatures, + runtime, }: { isDev: boolean hasServerComponents: boolean - hasConcurrentFeatures: boolean + runtime?: 'nodejs' | 'edge' } ): PagesMapping { const previousPages: PagesMapping = {} @@ -81,7 +81,7 @@ 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${hasConcurrentFeatures ? '-web' : ''}` + const documentPage = `_document${runtime ? '-concurrent' : ''}` if (isDev) { pages['/_app'] = `${PAGES_DIR_ALIAS}/_app` pages['/_error'] = `${PAGES_DIR_ALIAS}/_error` @@ -98,7 +98,7 @@ export function createPagesMapping( type Entrypoints = { client: webpack5.EntryObject server: webpack5.EntryObject - serverWeb: webpack5.EntryObject + edgeServer: webpack5.EntryObject } export function createEntrypoints( @@ -111,7 +111,7 @@ export function createEntrypoints( ): Entrypoints { const client: webpack5.EntryObject = {} const server: webpack5.EntryObject = {} - const serverWeb: webpack5.EntryObject = {} + const edgeServer: webpack5.EntryObject = {} const hasRuntimeConfig = Object.keys(config.publicRuntimeConfig).length > 0 || @@ -156,7 +156,7 @@ export function createEntrypoints( const isCustomError = isCustomErrorPage(page) const isFlight = isFlightPage(config, absolutePagePath) - const webServerRuntime = !!config.experimental.concurrentFeatures + const edgeRuntime = config.experimental.runtime === 'edge' if (page.match(MIDDLEWARE_ROUTE)) { const loaderOpts: MiddlewareLoaderOptions = { @@ -170,9 +170,9 @@ export function createEntrypoints( return } - if (webServerRuntime && !isReserved && !isCustomError && !isApiRoute) { + if (edgeRuntime && !isReserved && !isCustomError && !isApiRoute) { ssrEntries.set(clientBundlePath, { requireFlightManifest: isFlight }) - serverWeb[serverBundlePath] = finalizeEntrypoint({ + edgeServer[serverBundlePath] = finalizeEntrypoint({ name: '[name].js', value: `next-middleware-ssr-loader?${stringify({ dev: false, @@ -184,7 +184,7 @@ export function createEntrypoints( ...defaultServerlessOptions, } as any)}!`, isServer: false, - isServerWeb: true, + isEdgeServer: true, }) } @@ -198,14 +198,14 @@ export function createEntrypoints( serverlessLoaderOptions )}!` } else if (isApiRoute || target === 'server') { - if (!webServerRuntime || isReserved || isCustomError) { + if (!edgeRuntime || isReserved || isCustomError) { server[serverBundlePath] = [absolutePagePath] } } else if ( isLikeServerless && page !== '/_app' && page !== '/_document' && - !webServerRuntime + !edgeRuntime ) { const serverlessLoaderOptions: ServerlessLoaderQuery = { page, @@ -244,7 +244,7 @@ export function createEntrypoints( return { client, server, - serverWeb, + edgeServer, } } @@ -253,13 +253,13 @@ export function finalizeEntrypoint({ value, isServer, isMiddleware, - isServerWeb, + isEdgeServer, }: { isServer: boolean name: string value: ObjectValue isMiddleware?: boolean - isServerWeb?: boolean + isEdgeServer?: boolean }): ObjectValue { const entry = typeof value !== 'object' || Array.isArray(value) @@ -276,7 +276,7 @@ export function finalizeEntrypoint({ } } - if (isServerWeb) { + if (isEdgeServer) { const ssrMiddlewareEntry = { library: { name: ['_ENTRIES', `middleware_[name]`], diff --git a/packages/next/build/index.ts b/packages/next/build/index.ts index 8190ae3beebfb..d72e3b461b199 100644 --- a/packages/next/build/index.ts +++ b/packages/next/build/index.ts @@ -151,7 +151,11 @@ export default async function build( setGlobal('phase', PHASE_PRODUCTION_BUILD) setGlobal('distDir', distDir) - const hasConcurrentFeatures = !!config.experimental.concurrentFeatures + // Currently, when the runtime option is set (either `nodejs` or `edge`), + // we enable concurrent features (Fizz-related rendering architecture). + const runtime = config.experimental.runtime + const hasConcurrentFeatures = !!runtime + const hasServerComponents = hasConcurrentFeatures && !!config.experimental.serverComponents @@ -292,7 +296,7 @@ export default async function build( createPagesMapping(pagePaths, config.pageExtensions, { isDev: false, hasServerComponents, - hasConcurrentFeatures, + runtime, }) ) @@ -614,16 +618,16 @@ export default async function build( rewrites, runWebpackSpan, }), - hasConcurrentFeatures + runtime === 'edge' ? getBaseWebpackConfig(dir, { buildId, reactProductionProfiling, isServer: true, - webServerRuntime: true, + isEdgeRuntime: true, config, target, pagesDir, - entrypoints: entrypoints.serverWeb, + entrypoints: entrypoints.edgeServer, rewrites, runWebpackSpan, }) @@ -657,7 +661,7 @@ export default async function build( } } else { const serverResult = await runCompiler(configs[1], { runWebpackSpan }) - const serverWebResult = configs[2] + const edgeServerResult = configs[2] ? await runCompiler(configs[2], { runWebpackSpan }) : null @@ -665,12 +669,12 @@ export default async function build( warnings: [ ...clientResult.warnings, ...serverResult.warnings, - ...(serverWebResult?.warnings || []), + ...(edgeServerResult?.warnings || []), ], errors: [ ...clientResult.errors, ...serverResult.errors, - ...(serverWebResult?.errors || []), + ...(edgeServerResult?.errors || []), ], } } @@ -717,7 +721,7 @@ export default async function build( const moduleName = getUnresolvedModuleFromError(error) if (hasConcurrentFeatures && moduleName) { const err = new Error( - `Native Node.js APIs are not supported in the Edge Runtime with \`concurrentFeatures\` enabled. Found \`${moduleName}\` imported.\n\n` + `Native Node.js APIs are not supported in the Edge Runtime. Found \`${moduleName}\` imported.\n\n` ) as NextError err.code = 'EDGE_RUNTIME_UNSUPPORTED_API' throw err diff --git a/packages/next/build/output/index.ts b/packages/next/build/output/index.ts index 6e0572bb64a8e..9da97a6581a0c 100644 --- a/packages/next/build/output/index.ts +++ b/packages/next/build/output/index.ts @@ -12,7 +12,7 @@ export function startedDevelopmentServer(appUrl: string, bindAddr: string) { let previousClient: webpack5.Compiler | null = null let previousServer: webpack5.Compiler | null = null -let previousServerWeb: webpack5.Compiler | null = null +let previousEdgeServer: webpack5.Compiler | null = null type CompilerDiagnostics = { modules: number @@ -39,7 +39,7 @@ export type AmpPageStatus = { type BuildStatusStore = { client: WebpackStatus server: WebpackStatus - serverWeb?: WebpackStatus + edgeServer?: WebpackStatus trigger: string | undefined amp: AmpPageStatus } @@ -102,14 +102,14 @@ const buildStore = createStore() let buildWasDone = false let clientWasLoading = true let serverWasLoading = true -let serverWebWasLoading = false +let edgeServerWasLoading = false buildStore.subscribe((state) => { - const { amp, client, server, serverWeb, trigger } = state + const { amp, client, server, edgeServer, trigger } = state const { appUrl } = consoleStore.getState() - if (client.loading || server.loading || serverWeb?.loading) { + if (client.loading || server.loading || edgeServer?.loading) { consoleStore.setState( { bootstrap: false, @@ -121,12 +121,12 @@ buildStore.subscribe((state) => { ) clientWasLoading = (!buildWasDone && clientWasLoading) || client.loading serverWasLoading = (!buildWasDone && serverWasLoading) || server.loading - serverWebWasLoading = - (!buildWasDone && serverWasLoading) || !!serverWeb?.loading + edgeServerWasLoading = + (!buildWasDone && serverWasLoading) || !!edgeServer?.loading buildWasDone = false return } - if (serverWeb?.loading) return + if (edgeServer?.loading) return buildWasDone = true @@ -136,14 +136,14 @@ buildStore.subscribe((state) => { loading: false, typeChecking: false, partial: - clientWasLoading && (serverWasLoading || serverWebWasLoading) + clientWasLoading && (serverWasLoading || edgeServerWasLoading) ? 'client and server' : undefined, modules: (clientWasLoading ? client.modules : 0) + (serverWasLoading ? server.modules : 0) + - (serverWebWasLoading ? serverWeb?.modules || 0 : 0), - hasServerWeb: !!serverWeb, + (edgeServerWasLoading ? edgeServer?.modules || 0 : 0), + hasEdgeServer: !!edgeServer, } if (client.errors) { // Show only client errors @@ -165,12 +165,12 @@ buildStore.subscribe((state) => { } as OutputState, true ) - } else if (serverWeb && serverWeb.errors) { - // Show only serverWeb errors + } else if (edgeServer && edgeServer.errors) { + // Show only edge server errors consoleStore.setState( { ...partialState, - errors: serverWeb.errors, + errors: edgeServer.errors, warnings: null, } as OutputState, true @@ -180,7 +180,7 @@ buildStore.subscribe((state) => { const warnings = [ ...(client.warnings || []), ...(server.warnings || []), - ...((serverWeb && serverWeb.warnings) || []), + ...((edgeServer && edgeServer.warnings) || []), ].concat(formatAmpMessages(amp) || []) consoleStore.setState( @@ -223,12 +223,12 @@ export function ampValidation( export function watchCompilers( client: webpack5.Compiler, server: webpack5.Compiler, - serverWeb: webpack5.Compiler + edgeServer: webpack5.Compiler ) { if ( previousClient === client && previousServer === server && - previousServerWeb === serverWeb + previousEdgeServer === edgeServer ) { return } @@ -236,7 +236,7 @@ export function watchCompilers( buildStore.setState({ client: { loading: true }, server: { loading: true }, - serverWeb: serverWeb ? { loading: true } : undefined, + edgeServer: edgeServer ? { loading: true } : undefined, trigger: 'initial', }) @@ -295,10 +295,10 @@ export function watchCompilers( }) } }) - if (serverWeb) { - tapCompiler('serverWeb', serverWeb, (status) => { + if (edgeServer) { + tapCompiler('edgeServer', edgeServer, (status) => { buildStore.setState({ - serverWeb: status, + edgeServer: status, trigger: undefined, }) }) @@ -306,7 +306,7 @@ export function watchCompilers( previousClient = client previousServer = server - previousServerWeb = serverWeb + previousEdgeServer = edgeServer } export function reportTrigger(trigger: string) { diff --git a/packages/next/build/output/store.ts b/packages/next/build/output/store.ts index c97e47a9e9507..ff2edad64ed04 100644 --- a/packages/next/build/output/store.ts +++ b/packages/next/build/output/store.ts @@ -19,7 +19,7 @@ export type OutputState = modules: number errors: string[] | null warnings: string[] | null - hasServerWeb: boolean + hasEdgeServer: boolean } )) @@ -91,9 +91,9 @@ store.subscribe((state) => { } const moduleName = getUnresolvedModuleFromError(cleanError) - if (state.hasServerWeb && moduleName) { + if (state.hasEdgeServer && moduleName) { console.error( - `Native Node.js APIs are not supported in the Edge Runtime with \`concurrentFeatures\` enabled. Found \`${moduleName}\` imported.\n` + `Native Node.js APIs are not supported in the Edge Runtime. Found \`${moduleName}\` imported.\n` ) return } diff --git a/packages/next/build/utils.ts b/packages/next/build/utils.ts index 6c4ea4a0d7089..00c8d9ece3180 100644 --- a/packages/next/build/utils.ts +++ b/packages/next/build/utils.ts @@ -1116,7 +1116,7 @@ export function isFlightPage( if ( !( nextConfig.experimental.serverComponents && - nextConfig.experimental.concurrentFeatures + nextConfig.experimental.runtime ) ) return false diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index 6a16a2cf65f3b..235722e7d01c3 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -304,7 +304,7 @@ export default async function getBaseWebpackConfig( config, dev = false, isServer = false, - webServerRuntime = false, + isEdgeRuntime = false, pagesDir, target = 'server', reactProductionProfiling = false, @@ -317,7 +317,7 @@ export default async function getBaseWebpackConfig( config: NextConfigComplete dev?: boolean isServer?: boolean - webServerRuntime?: boolean + isEdgeRuntime?: boolean pagesDir: string target?: string reactProductionProfiling?: boolean @@ -352,6 +352,8 @@ export default async function getBaseWebpackConfig( const hasReactRoot: boolean = config.experimental.reactRoot || hasReact18 || isReactExperimental + const runtime = config.experimental.runtime + // Make sure reactRoot is enabled when react 18 is detected if (hasReactRoot) { config.experimental.reactRoot = true @@ -366,29 +368,36 @@ export default async function getBaseWebpackConfig( // It's fine to only mention React 18 here as we don't recommend people to try experimental. Log.warn('You have to use React 18 to use `experimental.reactRoot`.') } - if (!isServer && config.experimental.concurrentFeatures && !hasReactRoot) { + if (!isServer && runtime && !hasReactRoot) { throw new Error( - '`experimental.concurrentFeatures` requires `experimental.reactRoot` to be enabled along with React 18.' + '`experimental.runtime` requires `experimental.reactRoot` to be enabled along with React 18.' ) } - if ( - config.experimental.serverComponents && - !config.experimental.concurrentFeatures - ) { + if (config.experimental.serverComponents && !runtime) { throw new Error( - '`experimental.concurrentFeatures` is required to be enabled along with `experimental.serverComponents`.' + '`experimental.runtime` is required to be set along with `experimental.serverComponents`.' ) } - const hasConcurrentFeatures = - config.experimental.concurrentFeatures && hasReactRoot + + const targetWeb = isEdgeRuntime || !isServer + const hasConcurrentFeatures = !!runtime && hasReactRoot const hasServerComponents = hasConcurrentFeatures && !!config.experimental.serverComponents - const targetWeb = webServerRuntime || !isServer + const disableOptimizedLoading = hasConcurrentFeatures + ? true + : config.experimental.disableOptimizedLoading - if (webServerRuntime) { - Log.warn( - 'You are using the experimental Edge Runtime with `concurrentFeatures`.' - ) + if (!isServer) { + if (runtime === 'edge') { + Log.warn( + 'You are using the experimental Edge Runtime with `experimental.runtime`.' + ) + } + if (runtime === 'nodejs') { + Log.warn( + 'You are using the experimental Node.js Runtime with `experimental.runtime`.' + ) + } if (hasServerComponents) { Log.warn( 'You have experimental React Server Components enabled. Continue at your own risk.' @@ -562,7 +571,9 @@ export default async function getBaseWebpackConfig( prev.push(path.join(pagesDir, `_document.${ext}`)) return prev }, [] as string[]), - `next/dist/pages/_document${webServerRuntime ? '-web' : ''}.js`, + `next/dist/pages/_document${ + hasConcurrentFeatures ? '-concurrent' : '' + }.js`, ] } @@ -971,7 +982,7 @@ export default async function getBaseWebpackConfig( // TODO: should we warn/error for this instead? [ 'next', - ...(webServerRuntime + ...(isEdgeRuntime ? [ { 'next/dist/compiled/etag': '{}', @@ -1047,7 +1058,7 @@ export default async function getBaseWebpackConfig( ? dev ? false : ({ - filename: webServerRuntime ? 'chunks/[name].js' : '[name].js', + filename: isEdgeRuntime ? 'chunks/[name].js' : '[name].js', // allow to split entrypoints chunks: ({ name }: any) => !name?.match(MIDDLEWARE_ROUTE), // size of files is not so relevant for server build @@ -1108,12 +1119,12 @@ export default async function getBaseWebpackConfig( // auto which doesn't work in IE11 publicPath: `${config.assetPrefix || ''}/_next/`, path: - isServer && !dev && !webServerRuntime + isServer && !dev && !isEdgeRuntime ? path.join(outputPath, 'chunks') : outputPath, // On the server we don't use hashes filename: isServer - ? !dev && !webServerRuntime + ? !dev && !isEdgeRuntime ? `../[name].js` : `[name].js` : `static/chunks/${isDevFallback ? 'fallback/' : ''}[name]${ @@ -1178,6 +1189,7 @@ export default async function getBaseWebpackConfig( } as any, ] : []), + // Loaders for the client compilation when RSC is enabled. ...(hasServerComponents && !isServer ? [ { @@ -1192,7 +1204,10 @@ export default async function getBaseWebpackConfig( }, ] : []), - ...(hasServerComponents && webServerRuntime + // Loaders for the server compilation when RSC is enabled. + ...(hasServerComponents && + ((runtime === 'edge' && isEdgeRuntime) || + (runtime === 'nodejs' && isServer)) ? [ { ...codeCondition, @@ -1444,21 +1459,20 @@ export default async function getBaseWebpackConfig( resourceRegExp: /react-is/, contextRegExp: /next[\\/]dist[\\/]/, }), - ((isServerless && isServer) || webServerRuntime) && - new ServerlessPlugin(), + ((isServerless && isServer) || isEdgeRuntime) && new ServerlessPlugin(), isServer && - !webServerRuntime && + !isEdgeRuntime && new PagesManifestPlugin({ serverless: isLikeServerless, dev }), // MiddlewarePlugin should be after DefinePlugin so NEXT_PUBLIC_* // replacement is done before its process.env.* handling - (!isServer || webServerRuntime) && - new MiddlewarePlugin({ dev, webServerRuntime }), + (!isServer || isEdgeRuntime) && + new MiddlewarePlugin({ dev, isEdgeRuntime }), process.env.ENABLE_FILE_SYSTEM_API === '1' && - webServerRuntime && + isEdgeRuntime && new FunctionsManifestPlugin({ dev, pagesDir, - webServerRuntime, + isEdgeRuntime, pageExtensions: config.pageExtensions, }), isServer && new NextJsSsrImportPlugin(), @@ -1473,7 +1487,7 @@ export default async function getBaseWebpackConfig( config.optimizeFonts && !dev && isServer && - !webServerRuntime && + !isEdgeRuntime && (function () { const { FontStylesheetGatheringPlugin } = require('./webpack/plugins/font-stylesheet-gathering-plugin') as { @@ -1498,7 +1512,7 @@ export default async function getBaseWebpackConfig( }), hasServerComponents && !isServer && - new FlightManifestPlugin({ dev, clientComponentsRegex }), + new FlightManifestPlugin({ dev, clientComponentsRegex, runtime }), !dev && !isServer && new TelemetryPlugin( @@ -1605,14 +1619,14 @@ export default async function getBaseWebpackConfig( pageEnv: config.experimental.pageEnv, excludeDefaultMomentLocales: config.excludeDefaultMomentLocales, assetPrefix: config.assetPrefix, - disableOptimizedLoading: config.experimental.disableOptimizedLoading, + disableOptimizedLoading, target, - webServerRuntime, + isEdgeRuntime, reactProductionProfiling, webpack: !!config.webpack, hasRewrites, reactRoot: config.experimental.reactRoot, - concurrentFeatures: config.experimental.concurrentFeatures, + runtime, swcMinify: config.swcMinify, swcLoader: useSWCLoader, removeConsole: config.experimental.removeConsole, @@ -1705,7 +1719,7 @@ export default async function getBaseWebpackConfig( customAppFile: new RegExp(escapeStringRegexp(path.join(pagesDir, `_app`))), isDevelopment: dev, isServer, - webServerRuntime, + isEdgeRuntime, targetWeb, assetPrefix: config.assetPrefix || '', sassOptions: config.sassOptions, @@ -2070,7 +2084,7 @@ export default async function getBaseWebpackConfig( } delete entry['main.js'] - if (!webServerRuntime) { + if (!isEdgeRuntime) { for (const name of Object.keys(entry)) { entry[name] = finalizeEntrypoint({ value: entry[name], diff --git a/packages/next/build/webpack/config/blocks/base.ts b/packages/next/build/webpack/config/blocks/base.ts index 34ee68b412520..fe7a9ddca9e0b 100644 --- a/packages/next/build/webpack/config/blocks/base.ts +++ b/packages/next/build/webpack/config/blocks/base.ts @@ -8,15 +8,15 @@ export const base = curry(function base( ) { config.mode = ctx.isDevelopment ? 'development' : 'production' config.name = ctx.isServer - ? ctx.webServerRuntime - ? 'server-web' + ? ctx.isEdgeRuntime + ? 'edge-server' : 'server' : 'client' // @ts-ignore TODO webpack 5 typings config.target = !ctx.targetWeb ? 'node12.22' - : ctx.webServerRuntime + : ctx.isEdgeRuntime ? ['web', 'es6'] : ['web', 'es5'] @@ -25,7 +25,7 @@ export const base = curry(function base( if (process.env.__NEXT_TEST_MODE && !process.env.__NEXT_TEST_WITH_DEVTOOL) { config.devtool = false } else { - if (!ctx.webServerRuntime) { + if (!ctx.isEdgeRuntime) { // `eval-source-map` provides full-fidelity source maps for the // original source, including columns and original variable names. // This is desirable so the in-browser debugger can correctly pause diff --git a/packages/next/build/webpack/config/index.ts b/packages/next/build/webpack/config/index.ts index bb30f66f79cf5..7cf5bedc109f0 100644 --- a/packages/next/build/webpack/config/index.ts +++ b/packages/next/build/webpack/config/index.ts @@ -13,7 +13,7 @@ export async function build( customAppFile, isDevelopment, isServer, - webServerRuntime, + isEdgeRuntime, targetWeb, assetPrefix, sassOptions, @@ -27,7 +27,7 @@ export async function build( customAppFile: RegExp isDevelopment: boolean isServer: boolean - webServerRuntime: boolean + isEdgeRuntime: boolean targetWeb: boolean assetPrefix: string sassOptions: any @@ -44,7 +44,7 @@ export async function build( isDevelopment, isProduction: !isDevelopment, isServer, - webServerRuntime, + isEdgeRuntime, isClient: !isServer, targetWeb, assetPrefix: assetPrefix diff --git a/packages/next/build/webpack/config/utils.ts b/packages/next/build/webpack/config/utils.ts index 2680efa13bb90..15de0b9a068ef 100644 --- a/packages/next/build/webpack/config/utils.ts +++ b/packages/next/build/webpack/config/utils.ts @@ -11,7 +11,7 @@ export type ConfigurationContext = { isServer: boolean isClient: boolean - webServerRuntime: boolean + isEdgeRuntime: boolean targetWeb: boolean assetPrefix: string diff --git a/packages/next/build/webpack/loaders/next-flight-server-loader.ts b/packages/next/build/webpack/loaders/next-flight-server-loader.ts index 8d5b84927e235..f3243d1dc8c72 100644 --- a/packages/next/build/webpack/loaders/next-flight-server-loader.ts +++ b/packages/next/build/webpack/loaders/next-flight-server-loader.ts @@ -144,22 +144,23 @@ export default async function transformSource( ) /** - * Server side component module output: + * For .server.js files, we handle this loader differently. * - * export default function ServerComponent() { ... } - * + export const __rsc_noop__=()=>{ ... } - * + ServerComponent.__next_rsc__=1; + * Server compilation output: + * export default function ServerComponent() { ... } + * export const __rsc_noop__ = () => { ... } + * ServerComponent.__next_rsc__ = 1 + * ServerComponent.__webpack_require__ = __webpack_require__ * - * Client side component module output: - * - * The function body of ServerComponent will be removed + * Client compilation output: + * The function body of Server Component will be removed */ const noop = `export const __rsc_noop__=()=>{${imports.join(';')}}` const defaultExportNoop = isClientCompilation ? `export default function ${defaultExportName}(){}\n${defaultExportName}.__next_rsc__=1;` : defaultExportName - ? `${defaultExportName}.__next_rsc__=1;` + ? `${defaultExportName}.__next_rsc__=1;${defaultExportName}.__webpack_require__=__webpack_require__;` : '' const transformed = transformedSource + '\n' + noop + '\n' + defaultExportNoop diff --git a/packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts b/packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts index b74d8a3be093b..6fb65f84139b6 100644 --- a/packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts +++ b/packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts @@ -69,8 +69,8 @@ export function getRender({ webServerConfig: { extendRenderOpts: { buildId, + runtime: 'edge', supportsDynamicHTML: true, - concurrentFeatures: true, disableOptimizedLoading: true, serverComponentManifest, }, @@ -139,7 +139,7 @@ export function getRender({ // @TODO: We should move this into server/render. if (Document.getInitialProps) { const err = new Error( - '`getInitialProps` in Document component is not supported with `concurrentFeatures` enabled.' + '`getInitialProps` in Document component is not supported with the Edge Runtime.' ) return sendError(req, err) } diff --git a/packages/next/build/webpack/loaders/next-serverless-loader/page-handler.ts b/packages/next/build/webpack/loaders/next-serverless-loader/page-handler.ts index 5c7317d38b24d..968024c4683ac 100644 --- a/packages/next/build/webpack/loaders/next-serverless-loader/page-handler.ts +++ b/packages/next/build/webpack/loaders/next-serverless-loader/page-handler.ts @@ -193,7 +193,6 @@ export function getPageHandler(ctx: ServerlessHandlerCtx) { domainLocales: i18n?.domains, optimizeImages: process.env.__NEXT_OPTIMIZE_IMAGES, optimizeCss: process.env.__NEXT_OPTIMIZE_CSS, - concurrentFeatures: process.env.__NEXT_CONCURRENT_FEATURES, crossOrigin: process.env.__NEXT_CROSS_ORIGIN, }, options diff --git a/packages/next/build/webpack/plugins/flight-manifest-plugin.ts b/packages/next/build/webpack/plugins/flight-manifest-plugin.ts index 1a525c3fed253..ef01915b4b350 100644 --- a/packages/next/build/webpack/plugins/flight-manifest-plugin.ts +++ b/packages/next/build/webpack/plugins/flight-manifest-plugin.ts @@ -18,12 +18,14 @@ import { MIDDLEWARE_FLIGHT_MANIFEST } from '../../../shared/lib/constants' type Options = { dev: boolean clientComponentsRegex: RegExp + runtime?: 'nodejs' | 'edge' } const PLUGIN_NAME = 'FlightManifestPlugin' export class FlightManifestPlugin { dev: boolean = false + runtime?: 'nodejs' | 'edge' clientComponentsRegex: RegExp constructor(options: Options) { @@ -31,6 +33,7 @@ export class FlightManifestPlugin { this.dev = options.dev } this.clientComponentsRegex = options.clientComponentsRegex + this.runtime = options.runtime } apply(compiler: any) { @@ -120,9 +123,13 @@ export class FlightManifestPlugin { }) }) - const output = `self.__RSC_MANIFEST=` + JSON.stringify(json) - assets[`server/${MIDDLEWARE_FLIGHT_MANIFEST}.js`] = new sources.RawSource( - output - ) + const output = + (this.runtime === 'edge' ? 'self.__RSC_MANIFEST=' : '') + + JSON.stringify(json) + assets[ + `server/${MIDDLEWARE_FLIGHT_MANIFEST}${ + this.runtime === 'edge' ? '.js' : '.json' + }` + ] = new sources.RawSource(output) } } diff --git a/packages/next/build/webpack/plugins/functions-manifest-plugin.ts b/packages/next/build/webpack/plugins/functions-manifest-plugin.ts index 6e27b84d5ab72..4a5cf366e1470 100644 --- a/packages/next/build/webpack/plugins/functions-manifest-plugin.ts +++ b/packages/next/build/webpack/plugins/functions-manifest-plugin.ts @@ -28,23 +28,23 @@ export default class FunctionsManifestPlugin { dev: boolean pagesDir: string pageExtensions: string[] - webServerRuntime: boolean + isEdgeRuntime: boolean pagesRuntime: Map constructor({ dev, pagesDir, pageExtensions, - webServerRuntime, + isEdgeRuntime, }: { dev: boolean pagesDir: string pageExtensions: string[] - webServerRuntime: boolean + isEdgeRuntime: boolean }) { this.dev = dev this.pagesDir = pagesDir - this.webServerRuntime = webServerRuntime + this.isEdgeRuntime = isEdgeRuntime this.pageExtensions = pageExtensions this.pagesRuntime = new Map() } @@ -53,20 +53,20 @@ export default class FunctionsManifestPlugin { compilation: webpack5.Compilation, assets: any, envPerRoute: Map, - webServerRuntime: boolean + isEdgeRuntime: boolean ) { const functionsManifest: FunctionsManifest = { version: 1, pages: {}, } - const infos = getEntrypointInfo(compilation, envPerRoute, webServerRuntime) + const infos = getEntrypointInfo(compilation, envPerRoute, isEdgeRuntime) infos.forEach((info) => { const { page } = info // TODO: use global default runtime instead of 'web' const pageRuntime = this.pagesRuntime.get(page) const isWebRuntime = - pageRuntime === 'edge' || (this.webServerRuntime && !pageRuntime) + pageRuntime === 'edge' || (this.isEdgeRuntime && !pageRuntime) functionsManifest.pages[page] = { // Not assign if it's nodejs runtime, project configured node version is used instead ...(isWebRuntime && { runtime: 'web' }), @@ -74,8 +74,7 @@ export default class FunctionsManifestPlugin { } }) - const assetPath = - (this.webServerRuntime ? '' : 'server/') + FUNCTIONS_MANIFEST + const assetPath = (this.isEdgeRuntime ? '' : 'server/') + FUNCTIONS_MANIFEST assets[assetPath] = new sources.RawSource( JSON.stringify(functionsManifest, null, 2) ) @@ -149,7 +148,7 @@ export default class FunctionsManifestPlugin { collectAssets(compiler, this.createAssets.bind(this), { dev: this.dev, pluginName: PLUGIN_NAME, - webServerRuntime: this.webServerRuntime, + isEdgeRuntime: this.isEdgeRuntime, }) } } diff --git a/packages/next/build/webpack/plugins/middleware-plugin.ts b/packages/next/build/webpack/plugins/middleware-plugin.ts index 07c1710528eaf..7ada45ac32d47 100644 --- a/packages/next/build/webpack/plugins/middleware-plugin.ts +++ b/packages/next/build/webpack/plugins/middleware-plugin.ts @@ -52,7 +52,7 @@ function getPageFromEntrypointName(pagePath: string) { export function getEntrypointInfo( compilation: webpack5.Compilation, envPerRoute: Map, - webServerRuntime: boolean + isEdgeRuntime: boolean ) { const entrypoints = compilation.entrypoints const infos = [] @@ -61,8 +61,8 @@ export function getEntrypointInfo( const ssrEntryInfo = ssrEntries.get(entrypoint.name) - if (ssrEntryInfo && !webServerRuntime) continue - if (!ssrEntryInfo && webServerRuntime) continue + if (ssrEntryInfo && !isEdgeRuntime) continue + if (!ssrEntryInfo && isEdgeRuntime) continue const page = getPageFromEntrypointName(entrypoint.name) @@ -98,26 +98,26 @@ export function getEntrypointInfo( export default class MiddlewarePlugin { dev: boolean - webServerRuntime: boolean + isEdgeRuntime: boolean constructor({ dev, - webServerRuntime, + isEdgeRuntime, }: { dev: boolean - webServerRuntime: boolean + isEdgeRuntime: boolean }) { this.dev = dev - this.webServerRuntime = webServerRuntime + this.isEdgeRuntime = isEdgeRuntime } createAssets( compilation: webpack5.Compilation, assets: any, envPerRoute: Map, - webServerRuntime: boolean + isEdgeRuntime: boolean ) { - const infos = getEntrypointInfo(compilation, envPerRoute, webServerRuntime) + const infos = getEntrypointInfo(compilation, envPerRoute, isEdgeRuntime) infos.forEach((info) => { middlewareManifest.middleware[info.page] = info }) @@ -134,9 +134,7 @@ export default class MiddlewarePlugin { ) assets[ - this.webServerRuntime - ? MIDDLEWARE_MANIFEST - : `server/${MIDDLEWARE_MANIFEST}` + this.isEdgeRuntime ? MIDDLEWARE_MANIFEST : `server/${MIDDLEWARE_MANIFEST}` ] = new sources.RawSource(JSON.stringify(middlewareManifest, null, 2)) } @@ -144,7 +142,7 @@ export default class MiddlewarePlugin { collectAssets(compiler, this.createAssets.bind(this), { dev: this.dev, pluginName: PLUGIN_NAME, - webServerRuntime: this.webServerRuntime, + isEdgeRuntime: this.isEdgeRuntime, }) } } @@ -155,12 +153,12 @@ export function collectAssets( compilation: webpack5.Compilation, assets: any, envPerRoute: Map, - webServerRuntime: boolean + isEdgeRuntime: boolean ) => void, options: { dev: boolean pluginName: string - webServerRuntime: boolean + isEdgeRuntime: boolean } ) { const wp = compiler.webpack @@ -377,12 +375,7 @@ export function collectAssets( stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS, }, (assets: any) => { - createAssets( - compilation, - assets, - envPerRoute, - options.webServerRuntime - ) + createAssets(compilation, assets, envPerRoute, options.isEdgeRuntime) } ) } diff --git a/packages/next/export/index.ts b/packages/next/export/index.ts index 36d6930318ad4..e7d7d758a26f5 100644 --- a/packages/next/export/index.ts +++ b/packages/next/export/index.ts @@ -381,7 +381,7 @@ export default async function exportApp( disableOptimizedLoading: nextConfig.experimental.disableOptimizedLoading, // Exported pages do not currently support dynamic HTML. supportsDynamicHTML: false, - concurrentFeatures: nextConfig.experimental.concurrentFeatures, + runtime: nextConfig.experimental.runtime, crossOrigin: nextConfig.crossOrigin, optimizeCss: nextConfig.experimental.optimizeCss, optimizeFonts: nextConfig.optimizeFonts, diff --git a/packages/next/pages/_document-web.tsx b/packages/next/pages/_document-concurrent.tsx similarity index 85% rename from packages/next/pages/_document-web.tsx rename to packages/next/pages/_document-concurrent.tsx index 2442154129350..8275efd253fe9 100644 --- a/packages/next/pages/_document-web.tsx +++ b/packages/next/pages/_document-concurrent.tsx @@ -1,4 +1,4 @@ -// Default _document page for web runtime +// Default Document for streaming features import React from 'react' import { Html, Head, Main, NextScript } from './_document' diff --git a/packages/next/pages/_document.tsx b/packages/next/pages/_document.tsx index 53f9a195dd2bf..ee8fe49fed2ce 100644 --- a/packages/next/pages/_document.tsx +++ b/packages/next/pages/_document.tsx @@ -495,9 +495,11 @@ export class Head extends Component< optimizeCss, optimizeFonts, optimizeImages, - concurrentFeatures, + runtime, } = this.context + const hasConcurrentFeatures = !!runtime + const disableRuntimeJS = unstable_runtimeJS === false const disableJsPreload = unstable_JsPreload === false || !disableOptimizedLoading @@ -663,7 +665,7 @@ export class Head extends Component< return ( - {!concurrentFeatures && this.context.isDevelopment && ( + {!hasConcurrentFeatures && this.context.isDevelopment && ( <>