diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index 98d73a83454b7..adbd6b55f4d63 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -246,10 +246,7 @@ pub async fn get_next_server_import_map( | ServerContextType::AppRSC { .. } | ServerContextType::AppRoute { .. } => { match mode { - NextMode::Build => { - import_map.insert_wildcard_alias("next/dist/server/", external); - import_map.insert_wildcard_alias("next/dist/shared/", external); - } + NextMode::Build => {} NextMode::DevServer => { // The sandbox can't be bundled and needs to be external import_map.insert_exact_alias("next/dist/server/web/sandbox", external); @@ -431,9 +428,11 @@ async fn insert_next_server_special_aliases( ); } (_, ServerContextType::PagesData { .. }) => {} - // In development, we *always* use the bundled version of React, even in - // SSR, since we're bundling Next.js alongside it. - (NextMode::DevServer, ServerContextType::AppSSR { app_dir }) => { + // the logic closely follows the one in createRSCAliases in webpack-config.ts + ( + NextMode::DevServer | NextMode::Build | NextMode::Development, + ServerContextType::AppSSR { app_dir }, + ) => { import_map.insert_exact_alias( "@opentelemetry/api", // TODO(WEB-625) this actually need to prefer the local version of @@ -441,51 +440,126 @@ async fn insert_next_server_special_aliases( request_to_import_mapping(app_dir, "next/dist/compiled/@opentelemetry/api"), ); import_map.insert_exact_alias( - "react", - passthrough_external_if_node(app_dir, "next/dist/compiled/react"), + "styled-jsx", + passthrough_external_if_node(app_dir, "next/dist/compiled/styled-jsx"), ); import_map.insert_wildcard_alias( - "react/", - passthrough_external_if_node(app_dir, "next/dist/compiled/react/*"), + "styled-jsx/", + passthrough_external_if_node(app_dir, "next/dist/compiled/styled-jsx/*"), + ); + import_map.insert_exact_alias( + "react/jsx-runtime", + request_to_import_mapping( + app_dir, + match runtime { + NextRuntime::Edge => "next/dist/compiled/react/jsx-runtime", + NextRuntime::NodeJs => { + "next/dist/server/future/route-modules/app-page/vendored/shared/\ + react-jsx-runtime" + } + }, + ), + ); + import_map.insert_exact_alias( + "react/jsx-dev-runtime", + request_to_import_mapping( + app_dir, + match runtime { + NextRuntime::Edge => "next/dist/compiled/react/jsx-dev-runtime", + NextRuntime::NodeJs => { + "next/dist/server/future/route-modules/app-page/vendored/shared/\ + react-jsx-dev-runtime" + } + }, + ), + ); + import_map.insert_exact_alias( + "react", + request_to_import_mapping( + app_dir, + match runtime { + NextRuntime::Edge => "next/dist/compiled/react", + NextRuntime::NodeJs => { + "next/dist/server/future/route-modules/app-page/vendored/ssr/react" + } + }, + ), ); import_map.insert_exact_alias( "react-dom", - passthrough_external_if_node( + request_to_import_mapping( app_dir, - "next/dist/compiled/react-dom/server-rendering-stub.js", + match runtime { + NextRuntime::Edge => "next/dist/compiled/react-dom", + NextRuntime::NodeJs => { + "next/dist/server/future/route-modules/app-page/vendored/ssr/react-dom" + } + }, ), ); - import_map.insert_wildcard_alias( - "react-dom/", - passthrough_external_if_node(app_dir, "next/dist/compiled/react-dom/*"), + import_map.insert_exact_alias( + "react-server-dom-webpack/client.edge", + request_to_import_mapping( + app_dir, + match runtime { + NextRuntime::Edge => { + "next/dist/compiled/react-server-dom-webpack/client.edge" + } + NextRuntime::NodeJs => { + "next/dist/server/future/route-modules/app-page/vendored/ssr/\ + react-server-dom-webpack-client-edge" + } + }, + ), ); + // some code also imports react-server-dom-webpack/client on the server + // it should never run so it's fine to just point it to the same place as + // react-server-dom-webpack/client.edge import_map.insert_exact_alias( - "styled-jsx", - passthrough_external_if_node(app_dir, "next/dist/compiled/styled-jsx"), + "react-server-dom-webpack/client", + request_to_import_mapping( + app_dir, + match runtime { + NextRuntime::Edge => { + "next/dist/compiled/react-server-dom-webpack/client.edge" + } + NextRuntime::NodeJs => { + "next/dist/server/future/route-modules/app-page/vendored/ssr/\ + react-server-dom-webpack-client-edge" + } + }, + ), ); - import_map.insert_wildcard_alias( - "styled-jsx/", - passthrough_external_if_node(app_dir, "next/dist/compiled/styled-jsx/*"), + // not essential but we're providing this alias for people who might use it. + // A note here is that this will point toward the ReactDOMServer on the SSR + // layer TODO: add the rests + import_map.insert_exact_alias( + "react-dom/server", + request_to_import_mapping( + app_dir, + match runtime { + NextRuntime::Edge => "next/dist/compiled/react-dom/server.edge", + NextRuntime::NodeJs => { + "next/dist/server/future/route-modules/app-page/vendored/ssr/\ + react-dom-server-edge" + } + }, + ), ); - import_map.insert_wildcard_alias( - "react-server-dom-webpack/", - passthrough_external_if_node( + import_map.insert_exact_alias( + "react-dom/server.edge", + request_to_import_mapping( app_dir, - "next/dist/compiled/react-server-dom-webpack/*", + match runtime { + NextRuntime::Edge => "next/dist/compiled/react-dom/server.edge", + NextRuntime::NodeJs => { + "next/dist/server/future/route-modules/app-page/vendored/ssr/\ + react-dom-server-edge" + } + }, ), ); } - - // NOTE(alexkirsz) This logic maps loosely to - // `next.js/packages/next/src/build/webpack-config.ts`, where: - // - // ## RSC - // - // * always bundles - // * maps react -> react/shared-subset (through the "react-server" exports condition) - // * maps react-dom -> react-dom/server-rendering-stub - // * passes through (react|react-dom|react-server-dom-webpack)/(.*) to - // next/dist/compiled/$1/$2 ( NextMode::Build | NextMode::Development | NextMode::DevServer, ServerContextType::AppRSC { app_dir, .. } | ServerContextType::AppRoute { app_dir }, @@ -496,72 +570,103 @@ async fn insert_next_server_special_aliases( // @opentelemetry/api request_to_import_mapping(app_dir, "next/dist/compiled/@opentelemetry/api"), ); - if matches!(ty, ServerContextType::AppRSC { .. }) { - import_map.insert_exact_alias( - "react", - request_to_import_mapping( - app_dir, - "next/dist/compiled/react/react.shared-subset", - ), - ); - } else { - import_map.insert_exact_alias( - "react", - request_to_import_mapping(app_dir, "next/dist/compiled/react"), - ); - } + import_map.insert_exact_alias( - "react-dom", + "react/jsx-runtime", request_to_import_mapping( app_dir, - "next/dist/compiled/react-dom/server-rendering-stub", + match runtime { + NextRuntime::Edge => "next/dist/compiled/react/jsx-runtime", + NextRuntime::NodeJs => { + "next/dist/server/future/route-modules/app-page/vendored/shared/\ + react-jsx-runtime" + } + }, ), ); - for (wildcard_alias, request) in [ - ("react/", "next/dist/compiled/react/*"), - ("react-dom/", "next/dist/compiled/react-dom/*"), - ( - "react-server-dom-webpack/", - "next/dist/compiled/react-server-dom-webpack/*", + import_map.insert_exact_alias( + "react/jsx-dev-runtime", + request_to_import_mapping( + app_dir, + match runtime { + NextRuntime::Edge => "next/dist/compiled/react/jsx-dev-runtime", + NextRuntime::NodeJs => { + "next/dist/server/future/route-modules/app-page/vendored/shared/\ + react-jsx-dev-runtime" + } + }, ), - ] { - import_map.insert_wildcard_alias( - wildcard_alias, - request_to_import_mapping(app_dir, request), - ); - } - } - // ## SSR - // - // * always uses externals, to ensure we're using the same React instance as the Next.js - // runtime - // * maps react-dom -> react-dom/server-rendering-stub - // * passes through react and (react|react-dom|react-server-dom-webpack)/(.*) to - // next/dist/compiled/react and next/dist/compiled/$1/$2 resp. - (NextMode::Build | NextMode::Development, ServerContextType::AppSSR { app_dir }) => { + ); import_map.insert_exact_alias( "react", - external_if_node(app_dir, "next/dist/compiled/react"), + request_to_import_mapping( + app_dir, + match runtime { + NextRuntime::Edge => "next/dist/compiled/react", + NextRuntime::NodeJs => { + "next/dist/server/future/route-modules/app-page/vendored/rsc/react" + } + }, + ), ); import_map.insert_exact_alias( "react-dom", - external_if_node( + request_to_import_mapping( app_dir, - "next/dist/compiled/react-dom/server-rendering-stub", + match runtime { + NextRuntime::Edge => "next/dist/compiled/react-dom", + NextRuntime::NodeJs => { + "next/dist/server/future/route-modules/app-page/vendored/rsc/react-dom" + } + }, ), ); - - for (wildcard_alias, request) in [ - ("react/", "next/dist/compiled/react/*"), - ("react-dom/", "next/dist/compiled/react-dom/*"), - ( - "react-server-dom-webpack/", - "next/dist/compiled/react-server-dom-webpack/*", + import_map.insert_exact_alias( + "react-server-dom-webpack/server.edge", + request_to_import_mapping( + app_dir, + match runtime { + NextRuntime::Edge => { + "next/dist/compiled/react-server-dom-webpack/server.edge" + } + NextRuntime::NodeJs => { + "next/dist/server/future/route-modules/app-page/vendored/rsc/\ + react-server-dom-webpack-server-edge" + } + }, ), - ] { - let import_mapping = external_if_node(app_dir, request); - import_map.insert_wildcard_alias(wildcard_alias, import_mapping); - } + ); + import_map.insert_exact_alias( + "react-server-dom-webpack/server.node", + request_to_import_mapping( + app_dir, + match runtime { + NextRuntime::Edge => { + "next/dist/compiled/react-server-dom-webpack/server.node" + } + NextRuntime::NodeJs => { + "next/dist/server/future/route-modules/app-page/vendored/rsc/\ + react-server-dom-webpack-server-node" + } + }, + ), + ); + // not essential but we're providing this alias for people who might use it. + // A note here is that this will point toward the ReactDOMServer on the SSR + // layer TODO: add the rests + import_map.insert_exact_alias( + "react-dom/server.edge", + request_to_import_mapping( + app_dir, + match runtime { + NextRuntime::Edge => "next/dist/compiled/react-dom/server.edge", + NextRuntime::NodeJs => { + "next/dist/server/future/route-modules/app-page/vendored/ssr/\ + react-dom-server-edge" + } + }, + ), + ); } (_, ServerContextType::Middleware) => {} } diff --git a/packages/next-swc/crates/next-core/src/next_server/context.rs b/packages/next-swc/crates/next-core/src/next_server/context.rs index 1c6418a188314..7939dbe5c170f 100644 --- a/packages/next-swc/crates/next-core/src/next_server/context.rs +++ b/packages/next-swc/crates/next-core/src/next_server/context.rs @@ -48,7 +48,7 @@ use crate::{ next_shared::{ resolve::{ ModuleFeatureReportResolvePlugin, NextExternalResolvePlugin, - UnsupportedModulesResolvePlugin, + NextNodeSharedRuntimeResolvePlugin, UnsupportedModulesResolvePlugin, }, transforms::{ emotion::get_emotion_transform_plugin, get_relay_transform_plugin, @@ -125,6 +125,8 @@ pub async fn get_server_resolve_options_context( ); let next_external_plugin = NextExternalResolvePlugin::new(project_path); + let next_node_shared_runtime_plugin = + NextNodeSharedRuntimeResolvePlugin::new(project_path, Value::new(ty)); let plugins = match ty { ServerContextType::Pages { .. } | ServerContextType::PagesData { .. } => { @@ -133,6 +135,7 @@ pub async fn get_server_resolve_options_context( Vc::upcast(external_cjs_modules_plugin), Vc::upcast(unsupported_modules_resolve_plugin), Vc::upcast(next_external_plugin), + Vc::upcast(next_node_shared_runtime_plugin), ] } ServerContextType::AppSSR { .. } @@ -144,6 +147,7 @@ pub async fn get_server_resolve_options_context( Vc::upcast(server_component_externals_plugin), Vc::upcast(unsupported_modules_resolve_plugin), Vc::upcast(next_external_plugin), + Vc::upcast(next_node_shared_runtime_plugin), ] } }; @@ -175,7 +179,8 @@ fn defines(mode: NextMode) -> CompileTimeDefines { process.turbopack = true, process.env.NODE_ENV = mode.node_env(), process.env.__NEXT_CLIENT_ROUTER_FILTER_ENABLED = false, - process.env.NEXT_RUNTIME = "nodejs" + process.env.NEXT_RUNTIME = "nodejs", + process.env.__NEXT_EXPERIMENTAL_REACT = false, ) // TODO(WEB-937) there are more defines needed, see // packages/next/src/build/webpack-config.ts diff --git a/packages/next-swc/crates/next-core/src/next_shared/resolve.rs b/packages/next-swc/crates/next-core/src/next_shared/resolve.rs index 36866684af68f..8eebd1385ebd1 100644 --- a/packages/next-swc/crates/next-core/src/next_shared/resolve.rs +++ b/packages/next-swc/crates/next-core/src/next_shared/resolve.rs @@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet}; use anyhow::Result; use lazy_static::lazy_static; -use turbo_tasks::Vc; +use turbo_tasks::{Value, Vc}; use turbo_tasks_fs::glob::Glob; use turbopack_binding::{ turbo::tasks_fs::FileSystemPath, @@ -19,7 +19,7 @@ use turbopack_binding::{ }, }; -use crate::next_telemetry::ModuleFeatureTelemetry; +use crate::{next_server::ServerContextType, next_telemetry::ModuleFeatureTelemetry}; lazy_static! { static ref UNSUPPORTED_PACKAGES: HashSet<&'static str> = [].into(); @@ -122,10 +122,7 @@ impl ResolvePlugin for NextExternalResolvePlugin { fn after_resolve_condition(&self) -> Vc { ResolvePluginCondition::new( self.root.root(), - Glob::new( - "**/next/dist/**/*.{external,shared-runtime,runtime.dev,runtime.prod}.js" - .to_string(), - ), + Glob::new("**/next/dist/**/*.{external,runtime.dev,runtime.prod}.js".to_string()), ) } @@ -152,6 +149,70 @@ impl ResolvePlugin for NextExternalResolvePlugin { } } +#[turbo_tasks::value] +pub(crate) struct NextNodeSharedRuntimeResolvePlugin { + root: Vc, + context: ServerContextType, +} + +#[turbo_tasks::value_impl] +impl NextNodeSharedRuntimeResolvePlugin { + #[turbo_tasks::function] + pub fn new(root: Vc, context: Value) -> Vc { + let context = context.into_value(); + NextNodeSharedRuntimeResolvePlugin { root, context }.cell() + } +} + +#[turbo_tasks::value_impl] +impl ResolvePlugin for NextNodeSharedRuntimeResolvePlugin { + #[turbo_tasks::function] + fn after_resolve_condition(&self) -> Vc { + ResolvePluginCondition::new( + self.root.root(), + Glob::new("**/next/dist/**/*.shared-runtime.js".to_string()), + ) + } + + #[turbo_tasks::function] + async fn after_resolve( + &self, + fs_path: Vc, + _context: Vc, + _request: Vc, + ) -> Result> { + let stem = fs_path.file_stem().await?; + let stem = stem.as_deref().unwrap_or_default(); + let stem = stem.replace(".shared-runtime", ""); + + let resource_request = format!( + "next/dist/server/future/route-modules/{}/vendored/contexts/{}.js", + match self.context { + ServerContextType::Pages { .. } => "pages", + ServerContextType::AppRoute { .. } => "app-route", + ServerContextType::AppSSR { .. } | ServerContextType::AppRSC { .. } => "app-page", + _ => "unknown", + }, + stem + ); + + let raw_fs_path = &*fs_path.await?; + let path = raw_fs_path.path.to_string(); + + // Find the starting index of 'next/dist' and slice from that point. It should + // always be found since the glob pattern above is specific enough. + let starting_index = path.find("next/dist").unwrap(); + + let (base, _) = path.split_at(starting_index); + + let new_path = fs_path.root().join(format!("{base}/{resource_request}")); + + Ok(Vc::cell(Some( + ResolveResult::source(Vc::upcast(FileSource::new(new_path))).into(), + ))) + } +} + /// A resolver plugin tracks the usage of certain import paths, emit /// telemetry events if there is a match. #[turbo_tasks::value] diff --git a/packages/next/config.d.ts b/packages/next/config.d.ts index 2da1ee3c4029c..20c292fb467ef 100644 --- a/packages/next/config.d.ts +++ b/packages/next/config.d.ts @@ -1,3 +1,3 @@ -import getConfig from './dist/shared/lib/runtime-config.shared-runtime' -export * from './dist/shared/lib/runtime-config.shared-runtime' +import getConfig from './dist/shared/lib/runtime-config.external' +export * from './dist/shared/lib/runtime-config.external' export default getConfig diff --git a/packages/next/config.js b/packages/next/config.js index 6510748638097..668ee7c54f0e0 100644 --- a/packages/next/config.js +++ b/packages/next/config.js @@ -1 +1 @@ -module.exports = require('./dist/shared/lib/runtime-config.shared-runtime') +module.exports = require('./dist/shared/lib/runtime-config.external') diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts index 305eea8843844..b9261362bd4b6 100644 --- a/packages/next/src/build/index.ts +++ b/packages/next/src/build/index.ts @@ -147,11 +147,7 @@ import { startTypeChecking } from './type-check' import { generateInterceptionRoutesRewrites } from '../lib/generate-interception-routes-rewrites' import { buildDataRoute } from '../server/lib/router-utils/build-data-route' -import { - baseOverrides, - defaultOverrides, - experimentalOverrides, -} from '../server/import-overrides' +import { defaultOverrides } from '../server/import-overrides' import { initialize as initializeIncrementalCache } from '../server/lib/incremental-cache-server' import { nodeFs } from '../server/lib/node-fs-methods' import { getEsmLoaderPath } from '../server/lib/get-esm-loader-path' @@ -2100,12 +2096,6 @@ export default async function build( ) const sharedEntriesSet = [ - ...Object.values(baseOverrides).map((override) => - require.resolve(override) - ), - ...Object.values(experimentalOverrides).map((override) => - require.resolve(override) - ), ...(config.experimental.turbotrace ? [] : Object.keys(defaultOverrides).map((value) => @@ -2282,6 +2272,30 @@ export default async function build( } } } + + const moduleTypes = ['app-page', 'pages'] + + for (const type of moduleTypes) { + const contextDir = path.join( + path.dirname( + require.resolve( + `next/dist/server/future/route-modules/${type}/module` + ) + ), + 'vendored', + 'contexts' + ) + + for (const item of await fs.readdir(contextDir)) { + const itemPath = path.relative( + root, + path.join(contextDir, item) + ) + addToTracedFiles(root, itemPath, tracedFiles) + addToTracedFiles(root, itemPath, minimalTracedFiles) + } + } + await Promise.all([ fs.writeFile( nextServerTraceOutput, diff --git a/packages/next/src/build/utils.ts b/packages/next/src/build/utils.ts index ea34d4e7028d4..3af37d71a9907 100644 --- a/packages/next/src/build/utils.ts +++ b/packages/next/src/build/utils.ts @@ -1409,7 +1409,7 @@ export async function isPageStatic({ const isPageStaticSpan = trace('is-page-static-utils', parentId) return isPageStaticSpan .traceAsyncFn(async () => { - require('../shared/lib/runtime-config.shared-runtime').setConfig( + require('../shared/lib/runtime-config.external').setConfig( runtimeEnvConfig ) setHttpClientAndAgentOptions({ @@ -1695,9 +1695,7 @@ export async function hasCustomGetInitialProps( runtimeEnvConfig: any, checkingApp: boolean ): Promise { - require('../shared/lib/runtime-config.shared-runtime').setConfig( - runtimeEnvConfig - ) + require('../shared/lib/runtime-config.external').setConfig(runtimeEnvConfig) const components = await loadComponents({ distDir, @@ -1720,9 +1718,7 @@ export async function getDefinedNamedExports( distDir: string, runtimeEnvConfig: any ): Promise> { - require('../shared/lib/runtime-config.shared-runtime').setConfig( - runtimeEnvConfig - ) + require('../shared/lib/runtime-config.external').setConfig(runtimeEnvConfig) const components = await loadComponents({ distDir, page: page, diff --git a/packages/next/src/build/webpack-config.ts b/packages/next/src/build/webpack-config.ts index 73b4da713fafd..aa80e4c6fbff4 100644 --- a/packages/next/src/build/webpack-config.ts +++ b/packages/next/src/build/webpack-config.ts @@ -17,6 +17,7 @@ import { RSC_ACTION_CLIENT_WRAPPER_ALIAS, RSC_ACTION_VALIDATE_ALIAS, WEBPACK_RESOURCE_QUERIES, + WebpackLayerName, } from '../lib/constants' import { CustomRoutes } from '../lib/load-custom-routes.js' import { isEdgeRuntime } from '../lib/is-edge-runtime' @@ -85,8 +86,8 @@ const NEXT_PROJECT_ROOT_DIST_CLIENT = path.join( 'client' ) -const isWebpackServerLayer = (layer: string | null) => - Boolean(layer && WEBPACK_LAYERS.GROUP.server.includes(layer)) +const isWebpackServerLayer = (layer: WebpackLayerName | null) => + Boolean(layer && WEBPACK_LAYERS.GROUP.server.includes(layer as any)) if (parseInt(React.version) < 18) { throw new Error('Next.js requires react >= 18.2.0 to be installed.') @@ -106,13 +107,9 @@ const asyncStoragesRegex = const pathSeparators = '[/\\\\]' const optionalEsmPart = `((${pathSeparators}esm)?${pathSeparators})` -const sharedRuntimeFileEnd = '(\\.shared-runtime(\\.js)?)$' const externalFileEnd = '(\\.external(\\.js)?)$' const nextDist = `next${pathSeparators}dist` -const sharedRuntimePattern = new RegExp( - `${nextDist}${optionalEsmPart}.*${sharedRuntimeFileEnd}` -) const externalPattern = new RegExp( `${nextDist}${optionalEsmPart}.*${externalFileEnd}` ) @@ -196,6 +193,7 @@ export function getDefineEnv({ isNodeServer, middlewareMatchers, previewModeId, + useServerActions, }: { allowedRevalidateHeaderKeys: string[] | undefined clientRouterFilters: Parameters< @@ -212,6 +210,7 @@ export function getDefineEnv({ isNodeServer: boolean middlewareMatchers: MiddlewareMatcher[] | undefined previewModeId: string | undefined + useServerActions: boolean }) { return { // internal field to identify the plugin config @@ -374,6 +373,12 @@ export function getDefineEnv({ } : undefined), 'process.env.TURBOPACK': JSON.stringify(false), + ...(isNodeServer + ? { + 'process.env.__NEXT_EXPERIMENTAL_REACT': + JSON.stringify(useServerActions), + } + : undefined), } } @@ -387,35 +392,64 @@ function getReactProfilingInProduction() { function createRSCAliases( bundledReactChannel: string, opts: { + layer: WebpackLayerName & ('rsc' | 'ssr' | 'app-pages-browser') + isEdgeServer: boolean reactProductionProfiling: boolean - reactSharedSubset: boolean - reactDomServerRenderingStub: boolean reactServerCondition?: boolean } ) { - const alias: Record = { - react$: `next/dist/compiled/react${bundledReactChannel}`, - 'react-dom$': `next/dist/compiled/react-dom${bundledReactChannel}`, - 'react/jsx-runtime$': `next/dist/compiled/react${bundledReactChannel}/jsx-runtime`, - 'react/jsx-dev-runtime$': `next/dist/compiled/react${bundledReactChannel}/jsx-dev-runtime`, - 'react-dom/client$': `next/dist/compiled/react-dom${bundledReactChannel}/client`, - 'react-dom/server$': `next/dist/compiled/react-dom${bundledReactChannel}/server`, - 'react-dom/server.edge$': `next/dist/compiled/react-dom${bundledReactChannel}/server.edge`, - 'react-dom/server.browser$': `next/dist/compiled/react-dom${bundledReactChannel}/server.browser`, - 'react-server-dom-webpack/client$': `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/client`, - 'react-server-dom-webpack/client.edge$': `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/client.edge`, - 'react-server-dom-webpack/server.edge$': `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/server.edge`, - 'react-server-dom-webpack/server.node$': `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/server.node`, + let alias: Record = {} + if (opts.layer === 'app-pages-browser' || opts.isEdgeServer) { + alias = { + react$: `next/dist/compiled/react${bundledReactChannel}`, + 'react-dom$': `next/dist/compiled/react-dom${bundledReactChannel}`, + 'react/jsx-runtime$': `next/dist/compiled/react${bundledReactChannel}/jsx-runtime`, + 'react/jsx-dev-runtime$': `next/dist/compiled/react${bundledReactChannel}/jsx-dev-runtime`, + 'react-dom/client$': `next/dist/compiled/react-dom${bundledReactChannel}/client`, + 'react-dom/server$': `next/dist/compiled/react-dom${bundledReactChannel}/server`, + 'react-dom/server.edge$': `next/dist/compiled/react-dom${bundledReactChannel}/server.edge`, + 'react-dom/server.browser$': `next/dist/compiled/react-dom${bundledReactChannel}/server.browser`, + 'react-server-dom-webpack/client$': `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/client`, + 'react-server-dom-webpack/client.edge$': `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/client.edge`, + 'react-server-dom-webpack/server.edge$': `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/server.edge`, + 'react-server-dom-webpack/server.node$': `next/dist/compiled/react-server-dom-webpack${bundledReactChannel}/server.node`, + } + } else if (opts.layer === 'ssr') { + alias = { + 'react/jsx-runtime$': `next/dist/server/future/route-modules/app-page/vendored/shared/react-jsx-runtime`, + 'react/jsx-dev-runtime$': `next/dist/server/future/route-modules/app-page/vendored/shared/react-jsx-dev-runtime`, + react$: `next/dist/server/future/route-modules/app-page/vendored/${opts.layer}/react`, + 'react-dom$': `next/dist/server/future/route-modules/app-page/vendored/${opts.layer}/react-dom`, + 'react-dom/server.edge$': `next/dist/server/future/route-modules/app-page/vendored/${opts.layer}/react-dom-server-edge`, + 'react-server-dom-webpack/client.edge$': `next/dist/server/future/route-modules/app-page/vendored/${opts.layer}/react-server-dom-webpack-client-edge`, + // not essential but we're providing this alias for people who might use it + 'react-dom/server$': `next/dist/server/future/route-modules/app-page/vendored/${opts.layer}/react-dom-server-edge`, + } + } else if (opts.layer === 'rsc') { + alias = { + 'react/jsx-runtime$': `next/dist/server/future/route-modules/app-page/vendored/shared/react-jsx-runtime`, + 'react/jsx-dev-runtime$': `next/dist/server/future/route-modules/app-page/vendored/shared/react-jsx-dev-runtime`, + react$: `next/dist/server/future/route-modules/app-page/vendored/${opts.layer}/react`, + 'react-dom$': `next/dist/server/future/route-modules/app-page/vendored/${opts.layer}/react-dom`, + 'react-server-dom-webpack/server.edge$': `next/dist/server/future/route-modules/app-page/vendored/${opts.layer}/react-server-dom-webpack-server-edge`, + 'react-server-dom-webpack/server.node$': `next/dist/server/future/route-modules/app-page/vendored/${opts.layer}/react-server-dom-webpack-server-node`, + // not essential but we're providing this alias for people who might use it. + // A note here is that this will point toward the ReactDOMServer on the SSR layer + // TODO: add the rests + 'react-dom/server.edge$': `next/dist/server/future/route-modules/app-page/vendored/ssr/react-dom-server-edge`, + } + } else { + throw new Error(`Unexpected layer: ${opts.layer}`) } - if (opts.reactSharedSubset) { - alias[ - 'react$' - ] = `next/dist/compiled/react${bundledReactChannel}/react.shared-subset` - } - // Use server rendering stub for RSC - // x-ref: https://github.com/facebook/react/pull/25436 - if (opts.reactDomServerRenderingStub) { + if (opts.isEdgeServer) { + if (opts.layer === 'rsc') { + alias[ + 'react$' + ] = `next/dist/compiled/react${bundledReactChannel}/react.shared-subset` + } + // Use server rendering stub for RSC and SSR + // x-ref: https://github.com/facebook/react/pull/25436 alias[ 'react-dom$' ] = `next/dist/compiled/react-dom${bundledReactChannel}/server-rendering-stub` @@ -1129,14 +1163,6 @@ export default async function getBaseWebpackConfig( '@opentelemetry/api': 'next/dist/compiled/@opentelemetry/api', }), - ...(hasAppDir - ? createRSCAliases(bundledReactChannel, { - reactSharedSubset: false, - reactDomServerRenderingStub: false, - reactProductionProfiling, - }) - : {}), - ...(config.images.loaderFile ? { 'next/dist/shared/lib/image-loader': config.images.loaderFile, @@ -1314,7 +1340,7 @@ export default async function getBaseWebpackConfig( context: string, request: string, dependencyType: string, - layer: string | null, + layer: WebpackLayerName | null, getResolve: ( options: any ) => ( @@ -1339,35 +1365,15 @@ export default async function getBaseWebpackConfig( return `commonjs next/dist/lib/import-next-warning` } - const isAppLayer = [ - WEBPACK_LAYERS.reactServerComponents, - WEBPACK_LAYERS.serverSideRendering, - WEBPACK_LAYERS.appPagesBrowser, - WEBPACK_LAYERS.actionBrowser, - WEBPACK_LAYERS.appRouteHandler, - ].includes(layer!) - - if ( - request === 'react/jsx-dev-runtime' || - request === 'react/jsx-runtime' - ) { - if (isAppLayer) { - return `commonjs next/dist/compiled/${request.replace( - 'react', - 'react' + bundledReactChannel - )}` - } - return - } - - // Special internal modules that must be bundled for Server Components. - if (layer === WEBPACK_LAYERS.reactServerComponents) { - // React needs to be bundled for Server Components so the special - // `react-server` export condition can be used. - if (reactPackagesRegex.test(request)) { - return - } - } + const isAppLayer = ( + [ + WEBPACK_LAYERS.reactServerComponents, + WEBPACK_LAYERS.serverSideRendering, + WEBPACK_LAYERS.appPagesBrowser, + WEBPACK_LAYERS.actionBrowser, + WEBPACK_LAYERS.appRouteHandler, + ] as WebpackLayerName[] + ).includes(layer!) // Relative requires don't need custom resolution, because they // are relative to requests we've already resolved here. @@ -1378,25 +1384,7 @@ export default async function getBaseWebpackConfig( return `commonjs ${request}` } - if (reactPackagesRegex.test(request)) { - // override react-dom to server-rendering-stub for server - if ( - request === 'react-dom' && - (layer === WEBPACK_LAYERS.serverSideRendering || - layer === WEBPACK_LAYERS.reactServerComponents || - layer === WEBPACK_LAYERS.actionBrowser) - ) { - request = `next/dist/compiled/react-dom${bundledReactChannel}/server-rendering-stub` - } else if (isAppLayer) { - request = - 'next/dist/compiled/' + - request.replace( - /^(react-server-dom-webpack|react-dom|react)/, - (name) => { - return name + bundledReactChannel - } - ) - } + if (reactPackagesRegex.test(request) && !isAppLayer) { return `commonjs ${request}` } @@ -1432,7 +1420,6 @@ export default async function getBaseWebpackConfig( * will rewrite the require to the correct bundle location depending on the layer at which the file is being used. */ const resolveNextExternal = (localRes: string) => { - const isSharedRuntime = sharedRuntimePattern.test(localRes) const isExternal = externalPattern.test(localRes) // if the file ends with .external, we need to make it a commonjs require in all cases @@ -1442,42 +1429,6 @@ export default async function getBaseWebpackConfig( // otherwise NFT will get tripped up return `commonjs ${localRes.replace(/.*?next[/\\]dist/, 'next/dist')}` } - // if the file ends with .shared-runtime, we need to make it point to the correct bundle depending on the layer - // this is because each shared-runtime files are unique per bundle, so if you use app-router context in pages, - // it'll be a different instance than the one used in the app-router runtime. - if (isSharedRuntime) { - if (dev) { - return `commonjs ${localRes}` - } - - const name = path.parse(localRes).name.replace('.shared-runtime', '') - - const camelCaseName = name.replace(/-([a-z])/g, (_, w) => - w.toUpperCase() - ) - - // there's no externals for API routes but if need be, they'll need to be added here and have - // their own layer - const runtime = - layer === 'app-route-handler' - ? 'app-route' - : isAppLayer - ? 'app-page' - : 'pages' - return [ - 'commonjs ' + - path.posix.join( - 'next', - 'dist', - 'compiled', - 'next-server', - `${runtime}.runtime.${dev ? 'dev' : 'prod'}` - ), - 'default', - 'sharedModules', - camelCaseName, - ] - } } // Don't bundle @vercel/og nodejs bundle for nodejs runtime. @@ -1522,15 +1473,6 @@ export default async function getBaseWebpackConfig( // Treat react packages and next internals as external for SSR layer, // also map react to builtin ones with require-hook. if (layer === WEBPACK_LAYERS.serverSideRendering) { - if (reactPackagesRegex.test(request)) { - return `commonjs next/dist/compiled/${request.replace( - /^(react-server-dom-webpack|react-dom|react)/, - (name) => { - return name + bundledReactChannel - } - )}` - } - const isRelative = request.startsWith('.') const fullRequest = isRelative ? path.join(context, request).replace(/\\/g, '/') @@ -1730,7 +1672,7 @@ export default async function getBaseWebpackConfig( context, request, dependencyType, - contextInfo.issuerLayer, + contextInfo.issuerLayer as WebpackLayerName, (options) => { const resolveFunction = getResolve(options) return (resolveContext: string, requestToResolve: string) => @@ -2157,11 +2099,11 @@ export default async function getBaseWebpackConfig( // react to the direct file path, not the package name. In that case the condition // will be ignored completely. alias: createRSCAliases(bundledReactChannel, { - reactSharedSubset: true, - reactDomServerRenderingStub: true, reactServerCondition: true, // No server components profiling reactProductionProfiling, + layer: WEBPACK_LAYERS.reactServerComponents, + isEdgeServer, }), }, use: { @@ -2220,10 +2162,10 @@ export default async function getBaseWebpackConfig( // It needs `conditionNames` here to require the proper asset, // when react is acting as dependency of compiled/react-dom. alias: createRSCAliases(bundledReactChannel, { - reactSharedSubset: true, - reactDomServerRenderingStub: true, reactServerCondition: true, reactProductionProfiling, + layer: WEBPACK_LAYERS.reactServerComponents, + isEdgeServer, }), }, }, @@ -2232,10 +2174,10 @@ export default async function getBaseWebpackConfig( issuerLayer: WEBPACK_LAYERS.serverSideRendering, resolve: { alias: createRSCAliases(bundledReactChannel, { - reactSharedSubset: false, - reactDomServerRenderingStub: true, reactServerCondition: false, reactProductionProfiling, + layer: WEBPACK_LAYERS.serverSideRendering, + isEdgeServer, }), }, }, @@ -2247,10 +2189,13 @@ export default async function getBaseWebpackConfig( resolve: { alias: createRSCAliases(bundledReactChannel, { // Only alias server rendering stub in client SSR layer. - reactSharedSubset: false, - reactDomServerRenderingStub: false, + // reactSharedSubset: false, + // reactDomServerRenderingStub: false, reactServerCondition: false, reactProductionProfiling, + // browser: isClient, + layer: WEBPACK_LAYERS.appPagesBrowser, + isEdgeServer, }), }, }, @@ -2483,6 +2428,35 @@ export default async function getBaseWebpackConfig( ].filter(Boolean), }, plugins: [ + isNodeServer && + new webpack.NormalModuleReplacementPlugin( + /\.\/(.+)\.shared-runtime$/, + function (resource) { + const moduleName = path.basename( + resource.request, + '.shared-runtime' + ) + const layer = resource.contextInfo.issuerLayer + + let runtime + + switch (layer) { + case WEBPACK_LAYERS.appRouteHandler: + runtime = 'app-route' + break + case WEBPACK_LAYERS.serverSideRendering: + case WEBPACK_LAYERS.reactServerComponents: + case WEBPACK_LAYERS.appPagesBrowser: + case WEBPACK_LAYERS.actionBrowser: + runtime = 'app-page' + break + default: + runtime = 'pages' + } + + resource.request = `next/dist/server/future/route-modules/${runtime}/vendored/contexts/${moduleName}` + } + ), dev && new MemoryWithGcCachePlugin({ maxGenerations: 5 }), dev && isClient && new ReactRefreshWebpackPlugin(webpack), // Makes sure `Buffer` and `process` are polyfilled in client and flight bundles (same behavior as webpack 4) @@ -2508,6 +2482,7 @@ export default async function getBaseWebpackConfig( isNodeServer, middlewareMatchers, previewModeId, + useServerActions, }) ), isClient && diff --git a/packages/next/src/build/webpack/loaders/next-flight-loader/action-client-wrapper.ts b/packages/next/src/build/webpack/loaders/next-flight-loader/action-client-wrapper.ts index a1095a8497f52..7288263bb4303 100644 --- a/packages/next/src/build/webpack/loaders/next-flight-loader/action-client-wrapper.ts +++ b/packages/next/src/build/webpack/loaders/next-flight-loader/action-client-wrapper.ts @@ -11,7 +11,7 @@ export function createServerReference(id: string) { // we use the default and let Webpack to resolve it to the correct version. // 1: https://github.com/vercel/next.js/blob/16eb80b0b0be13f04a6407943664b5efd8f3d7d0/packages/next/src/server/app-render/use-flight-response.tsx#L24-L26 const { createServerReference: createServerReferenceImpl } = ( - typeof window === 'undefined' + !!process.env.NEXT_RUNTIME ? // eslint-disable-next-line import/no-extraneous-dependencies require('react-server-dom-webpack/client.edge') : // eslint-disable-next-line import/no-extraneous-dependencies diff --git a/packages/next/src/build/webpack/plugins/nextjs-require-cache-hot-reloader.ts b/packages/next/src/build/webpack/plugins/nextjs-require-cache-hot-reloader.ts index 940ecd476ffe2..349a3af2c4d73 100644 --- a/packages/next/src/build/webpack/plugins/nextjs-require-cache-hot-reloader.ts +++ b/packages/next/src/build/webpack/plugins/nextjs-require-cache-hot-reloader.ts @@ -12,11 +12,10 @@ const originModules = [ require.resolve('../../../server/require'), require.resolve('../../../server/load-components'), require.resolve('../../../server/next-server'), - require.resolve('../../../server/app-render/use-flight-response'), - require.resolve('../../../compiled/react-server-dom-webpack/client.edge'), - require.resolve( - '../../../compiled/react-server-dom-webpack-experimental/client.edge' - ), + require.resolve('next/dist/compiled/next-server/app-page.runtime.dev.js'), + require.resolve('next/dist/compiled/next-server/app-route.runtime.dev.js'), + require.resolve('next/dist/compiled/next-server/pages.runtime.dev.js'), + require.resolve('next/dist/compiled/next-server/pages-api.runtime.dev.js'), ] const RUNTIME_NAMES = ['webpack-runtime', 'webpack-api-runtime'] @@ -48,19 +47,9 @@ function deleteFromRequireCache(filePath: string) { } export function deleteAppClientCache() { - // ensure we reset the cache for rsc components - // loaded via react-server-dom-webpack - const reactServerDomModId = require.resolve( - 'react-server-dom-webpack/client.edge' + deleteFromRequireCache( + require.resolve('next/dist/compiled/next-server/app-page.runtime.dev.js') ) - const reactServerDomMod = require.cache[reactServerDomModId] - - if (reactServerDomMod) { - for (const child of [...reactServerDomMod.children]) { - deleteFromRequireCache(child.id) - } - deleteFromRequireCache(reactServerDomModId) - } } export function deleteCache(filePath: string) { diff --git a/packages/next/src/client/components/router-reducer/fetch-server-response.ts b/packages/next/src/client/components/router-reducer/fetch-server-response.ts index 689d27df7798f..7e13551cbc42e 100644 --- a/packages/next/src/client/components/router-reducer/fetch-server-response.ts +++ b/packages/next/src/client/components/router-reducer/fetch-server-response.ts @@ -2,7 +2,15 @@ // @ts-ignore // eslint-disable-next-line import/no-extraneous-dependencies -import { createFromFetch } from 'react-server-dom-webpack/client' +// import { createFromFetch } from 'react-server-dom-webpack/client' +const { createFromFetch } = ( + !!process.env.NEXT_RUNTIME + ? // eslint-disable-next-line import/no-extraneous-dependencies + require('react-server-dom-webpack/client.edge') + : // eslint-disable-next-line import/no-extraneous-dependencies + require('react-server-dom-webpack/client') +) as typeof import('react-server-dom-webpack/client') + import type { FlightRouterState, FlightData, diff --git a/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts b/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts index 0c6caaba746ca..6fc0afbf06c25 100644 --- a/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts +++ b/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts @@ -12,10 +12,17 @@ import { } from '../../app-router-headers' import { createRecordFromThenable } from '../create-record-from-thenable' import { readRecordValue } from '../read-record-value' -// eslint-disable-next-line import/no-extraneous-dependencies -import { createFromFetch } from 'react-server-dom-webpack/client' -// eslint-disable-next-line import/no-extraneous-dependencies -import { encodeReply } from 'react-server-dom-webpack/client' +// // eslint-disable-next-line import/no-extraneous-dependencies +// import { createFromFetch } from 'react-server-dom-webpack/client' +// // eslint-disable-next-line import/no-extraneous-dependencies +// import { encodeReply } from 'react-server-dom-webpack/client' +const { createFromFetch, encodeReply } = ( + !!process.env.NEXT_RUNTIME + ? // eslint-disable-next-line import/no-extraneous-dependencies + require('react-server-dom-webpack/client.edge') + : // eslint-disable-next-line import/no-extraneous-dependencies + require('react-server-dom-webpack/client') +) as typeof import('react-server-dom-webpack/client') import { ReadonlyReducerState, diff --git a/packages/next/src/client/index.tsx b/packages/next/src/client/index.tsx index 45cdbf650e591..487386b781745 100644 --- a/packages/next/src/client/index.tsx +++ b/packages/next/src/client/index.tsx @@ -19,7 +19,7 @@ import { urlQueryToSearchParams, assign, } from '../shared/lib/router/utils/querystring' -import { setConfig } from '../shared/lib/runtime-config.shared-runtime' +import { setConfig } from '../shared/lib/runtime-config.external' import { getURL, loadGetInitialProps, @@ -43,7 +43,7 @@ import { adaptForAppRouterInstance, adaptForSearchParams, PathnameContextProviderAdapter, -} from '../shared/lib/router/adapters.shared-runtime' +} from '../shared/lib/router/adapters' import { SearchParamsContext } from '../shared/lib/hooks-client-context.shared-runtime' import onRecoverableError from './on-recoverable-error' import tracer from './tracing/tracer' diff --git a/packages/next/src/export/index.ts b/packages/next/src/export/index.ts index 7c2fc4ebd89db..f8f32f48d5418 100644 --- a/packages/next/src/export/index.ts +++ b/packages/next/src/export/index.ts @@ -730,6 +730,7 @@ export default async function exportApp( fetchCacheKeyPrefix: nextConfig.experimental.fetchCacheKeyPrefix, incrementalCacheHandlerPath: nextConfig.experimental.incrementalCacheHandlerPath, + serverActions: nextConfig.experimental.serverActions, }) for (const validation of result.ampValidations || []) { diff --git a/packages/next/src/export/worker.ts b/packages/next/src/export/worker.ts index 0a554e32da05e..7329d10687fe0 100644 --- a/packages/next/src/export/worker.ts +++ b/packages/next/src/export/worker.ts @@ -13,6 +13,7 @@ import type { OutgoingHttpHeaders } from 'http' // Polyfill fetch for the export worker. import '../server/node-polyfill-fetch' import '../server/node-environment' +process.env.NEXT_IS_EXPORT_WORKER = 'true' import { extname, join, dirname, sep, posix } from 'path' import fs, { promises } from 'fs' @@ -59,7 +60,7 @@ import { RSC, } from '../client/components/app-router-headers' -const envConfig = require('../shared/lib/runtime-config.shared-runtime') +const envConfig = require('../shared/lib/runtime-config.external') ;(globalThis as any).__NEXT_DATA__ = { nextExport: true, @@ -96,6 +97,7 @@ interface ExportPageInput { incrementalCacheHandlerPath?: string fetchCacheKeyPrefix?: string nextConfigOutput?: NextConfigComplete['output'] + serverActions?: boolean } interface ExportPageResults { @@ -152,6 +154,7 @@ export default async function exportPage({ fetchCache, fetchCacheKeyPrefix, incrementalCacheHandlerPath, + serverActions, }: ExportPageInput): Promise { setHttpClientAndAgentOptions({ httpAgentOptions, @@ -168,6 +171,9 @@ export default async function exportPage({ if (renderOpts.deploymentId) { process.env.NEXT_DEPLOYMENT_ID = renderOpts.deploymentId } + if (serverActions) { + process.env.__NEXT_EXPERIMENTAL_REACT = 'true' + } const { query: originalQuery = {} } = pathMap const { page } = pathMap const pathname = normalizeAppPath(page) @@ -406,7 +412,7 @@ export default async function exportPage({ // functions during runtime just for prefetching const { renderToHTMLOrFlight } = - require('../server/app-render/app-render') as typeof import('../server/app-render/app-render') + require('../server/future/route-modules/app-page/module.compiled') as typeof import('../server/app-render/app-render') req.headers[RSC.toLowerCase()] = '1' req.headers[NEXT_URL.toLowerCase()] = path req.headers[NEXT_ROUTER_PREFETCH.toLowerCase()] = '1' diff --git a/packages/next/src/lib/constants.ts b/packages/next/src/lib/constants.ts index 65370408b0bca..92702f6231c18 100644 --- a/packages/next/src/lib/constants.ts +++ b/packages/next/src/lib/constants.ts @@ -138,7 +138,10 @@ const WEBPACK_LAYERS_NAMES = { * The layer for the server bundle for App Route handlers. */ appRouteHandler: 'app-route-handler', -} +} as const + +export type WebpackLayerName = + (typeof WEBPACK_LAYERS_NAMES)[keyof typeof WEBPACK_LAYERS_NAMES] export const WEBPACK_LAYERS = { ...WEBPACK_LAYERS_NAMES, diff --git a/packages/next/src/server/app-render/use-flight-response.tsx b/packages/next/src/server/app-render/use-flight-response.tsx index 0f09406806fca..a7d0318eeb70c 100644 --- a/packages/next/src/server/app-render/use-flight-response.tsx +++ b/packages/next/src/server/app-render/use-flight-response.tsx @@ -21,10 +21,9 @@ export function useFlightResponse( return flightResponseRef.current } // react-server-dom-webpack/client.edge must not be hoisted for require cache clearing to work correctly - const { createFromReadableStream } = process.env.NEXT_MINIMAL - ? // @ts-ignore - __non_webpack_require__(`react-server-dom-webpack/client.edge`) - : require(`react-server-dom-webpack/client.edge`) + const { + createFromReadableStream, + } = require(`react-server-dom-webpack/client.edge`) const [renderStream, forwardStream] = req.tee() const res = createFromReadableStream(renderStream, { diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index 10bf0c1a9bbd3..7b61af7e1fcd7 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -51,7 +51,7 @@ import { } from '../shared/lib/constants' import { isDynamicRoute } from '../shared/lib/router/utils' import { checkIsOnDemandRevalidate } from './api-utils' -import { setConfig } from '../shared/lib/runtime-config.shared-runtime' +import { setConfig } from '../shared/lib/runtime-config.external' import { setRevalidateHeaders } from './send-payload/revalidate-headers' import { execOnce } from '../shared/lib/utils' diff --git a/packages/next/src/server/dev/static-paths-worker.ts b/packages/next/src/server/dev/static-paths-worker.ts index cc870052e9394..cd7d5305fa306 100644 --- a/packages/next/src/server/dev/static-paths-worker.ts +++ b/packages/next/src/server/dev/static-paths-worker.ts @@ -58,7 +58,7 @@ export async function loadStaticPaths({ fallback?: boolean | 'blocking' }> { // update work memory runtime-config - require('../../shared/lib/runtime-config.shared-runtime').setConfig(config) + require('../../shared/lib/runtime-config.external').setConfig(config) setHttpClientAndAgentOptions({ httpAgentOptions, }) diff --git a/packages/next/src/server/esm-loader.mts b/packages/next/src/server/esm-loader.mts index 313bde8b39aae..3e6649607068b 100644 --- a/packages/next/src/server/esm-loader.mts +++ b/packages/next/src/server/esm-loader.mts @@ -3,13 +3,10 @@ import module from 'module' const require = module.createRequire(import.meta.url) export function resolve(specifier: string, context: any, nextResolve: any) { - const { overrideReact, hookPropertyMap } = require(process.env.NEXT_YARN_PNP + const { hookPropertyMap } = require(process.env.NEXT_YARN_PNP ? './import-overrides' : 'next/dist/server/import-overrides') as typeof import('./import-overrides') - // In case the environment variable is set after the module is loaded. - overrideReact() - const hookResolved = hookPropertyMap.get(specifier) if (hookResolved) { specifier = hookResolved diff --git a/packages/next/src/server/future/route-modules/app-page/module.compiled.ts b/packages/next/src/server/future/route-modules/app-page/module.compiled.ts index 78601739acbe5..f25b70992b1df 100644 --- a/packages/next/src/server/future/route-modules/app-page/module.compiled.ts +++ b/packages/next/src/server/future/route-modules/app-page/module.compiled.ts @@ -1,11 +1,21 @@ if (process.env.NEXT_RUNTIME === 'edge') { module.exports = require('next/dist/server/future/route-modules/app-page/module.js') } else { - if (process.env.NODE_ENV === 'development') { - module.exports = require('next/dist/compiled/next-server/app-page.runtime.dev.js') - } else if (process.env.TURBOPACK) { - module.exports = require('next/dist/compiled/next-server/app-page-turbo.runtime.prod.js') + if (process.env.__NEXT_EXPERIMENTAL_REACT) { + if (process.env.NODE_ENV === 'development') { + module.exports = require('next/dist/compiled/next-server/app-page-experimental.runtime.dev.js') + } else if (process.env.TURBOPACK) { + module.exports = require('next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js') + } else { + module.exports = require('next/dist/compiled/next-server/app-page-experimental.runtime.prod.js') + } } else { - module.exports = require('next/dist/compiled/next-server/app-page.runtime.prod.js') + if (process.env.NODE_ENV === 'development') { + module.exports = require('next/dist/compiled/next-server/app-page.runtime.dev.js') + } else if (process.env.TURBOPACK) { + module.exports = require('next/dist/compiled/next-server/app-page-turbo.runtime.prod.js') + } else { + module.exports = require('next/dist/compiled/next-server/app-page.runtime.prod.js') + } } } diff --git a/packages/next/src/server/future/route-modules/app-page/module.ts b/packages/next/src/server/future/route-modules/app-page/module.ts index daa0291a1c8b4..5cc33c1a60376 100644 --- a/packages/next/src/server/future/route-modules/app-page/module.ts +++ b/packages/next/src/server/future/route-modules/app-page/module.ts @@ -11,7 +11,18 @@ import { type RouteModuleOptions, type RouteModuleHandleContext, } from '../route-module' -import * as sharedModules from './shared-modules' +import * as vendoredContexts from './vendored/contexts/entrypoints' + +let vendoredReactRSC +let vendoredReactSSR +let vendoredReactShared + +// the vendored Reacts are loaded from their original source in the edge runtime +if (process.env.NEXT_RUNTIME !== 'edge') { + vendoredReactRSC = require('./vendored/rsc/entrypoints') + vendoredReactSSR = require('./vendored/ssr/entrypoints') + vendoredReactShared = require('./vendored/shared/entrypoints') +} type AppPageUserlandModule = { /** @@ -35,8 +46,6 @@ export class AppPageRouteModule extends RouteModule< AppPageRouteDefinition, AppPageUserlandModule > { - static readonly sharedModules = sharedModules - public render( req: IncomingMessage, res: ServerResponse, @@ -52,6 +61,13 @@ export class AppPageRouteModule extends RouteModule< } } -export { renderToHTMLOrFlight } +const vendored = { + 'react-rsc': vendoredReactRSC, + 'react-ssr': vendoredReactSSR, + 'react-shared': vendoredReactShared, + contexts: vendoredContexts, +} + +export { renderToHTMLOrFlight, vendored } export default AppPageRouteModule diff --git a/packages/next/src/server/future/route-modules/app-page/shared-modules.ts b/packages/next/src/server/future/route-modules/app-page/shared-modules.ts deleted file mode 100644 index e986c1bad3894..0000000000000 --- a/packages/next/src/server/future/route-modules/app-page/shared-modules.ts +++ /dev/null @@ -1,13 +0,0 @@ -// the name of the export has to be the camelCase version of the file name (without the extension) -export * as headManagerContext from '../../../../shared/lib/head-manager-context.shared-runtime' -export * as serverInsertedHtml from '../../../../shared/lib/server-inserted-html.shared-runtime' -export * as appRouterContext from '../../../../shared/lib/app-router-context.shared-runtime' -export * as hooksClientContext from '../../../../shared/lib/hooks-client-context.shared-runtime' -export * as routerContext from '../../../../shared/lib/router-context.shared-runtime' -export * as htmlContext from '../../../../shared/lib/html-context.shared-runtime' -export * as ampContext from '../../../../shared/lib/amp-context.shared-runtime' -export * as adapters from '../../../../shared/lib/router/adapters.shared-runtime' -export * as loadableContext from '../../../../shared/lib/loadable-context.shared-runtime' -export * as imageConfigContext from '../../../../shared/lib/image-config-context.shared-runtime' -export * as runtimeConfig from '../../../../shared/lib/runtime-config.shared-runtime' -export * as loadable from '../../../../shared/lib/loadable.shared-runtime' diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/contexts/amp-context.ts b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/amp-context.ts new file mode 100644 index 0000000000000..474e4f387711e --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/amp-context.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].AmpContext diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/contexts/app-router-context.ts b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/app-router-context.ts new file mode 100644 index 0000000000000..a112b6b26738f --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/app-router-context.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].AppRouterContext diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/contexts/entrypoints.ts b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/entrypoints.ts new file mode 100644 index 0000000000000..52274993f0abc --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/entrypoints.ts @@ -0,0 +1,10 @@ +export * as HeadManagerContext from '../../../../../../shared/lib/head-manager-context.shared-runtime' +export * as ServerInsertedHtml from '../../../../../../shared/lib/server-inserted-html.shared-runtime' +export * as AppRouterContext from '../../../../../../shared/lib/app-router-context.shared-runtime' +export * as HooksClientContext from '../../../../../../shared/lib/hooks-client-context.shared-runtime' +export * as RouterContext from '../../../../../../shared/lib/router-context.shared-runtime' +export * as HtmlContext from '../../../../../../shared/lib/html-context.shared-runtime' +export * as AmpContext from '../../../../../../shared/lib/amp-context.shared-runtime' +export * as LoadableContext from '../../../../../../shared/lib/loadable-context.shared-runtime' +export * as ImageConfigContext from '../../../../../../shared/lib/image-config-context.shared-runtime' +export * as Loadable from '../../../../../../shared/lib/loadable.shared-runtime' diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/contexts/head-manager-context.ts b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/head-manager-context.ts new file mode 100644 index 0000000000000..b7f082e3339de --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/head-manager-context.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].HeadManagerContext diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/contexts/hooks-client-context.ts b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/hooks-client-context.ts new file mode 100644 index 0000000000000..29aa771033f15 --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/hooks-client-context.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].HooksClientContext diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/contexts/html-context.ts b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/html-context.ts new file mode 100644 index 0000000000000..ae1126abb6f99 --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/html-context.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].HtmlContext diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/contexts/image-config-context.ts b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/image-config-context.ts new file mode 100644 index 0000000000000..3537107ae9982 --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/image-config-context.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].ImageConfigContext diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/contexts/loadable-context.ts b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/loadable-context.ts new file mode 100644 index 0000000000000..de9e07464c6fb --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/loadable-context.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].LoadableContext diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/contexts/loadable.ts b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/loadable.ts new file mode 100644 index 0000000000000..f67d05a251655 --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/loadable.ts @@ -0,0 +1 @@ +module.exports = require('../../module.compiled').vendored['contexts'].Loadable diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/contexts/router-context.ts b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/router-context.ts new file mode 100644 index 0000000000000..5a2f92e05309e --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/router-context.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].RouterContext diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/contexts/server-inserted-html.ts b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/server-inserted-html.ts new file mode 100644 index 0000000000000..3c488b0db8ee3 --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/contexts/server-inserted-html.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].ServerInsertedHtml diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/rsc/entrypoints.ts b/packages/next/src/server/future/route-modules/app-page/vendored/rsc/entrypoints.ts new file mode 100644 index 0000000000000..1d1273b91e610 --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/rsc/entrypoints.ts @@ -0,0 +1,15 @@ +import * as React from 'react' + +import * as ReactDOM from 'react-dom/server-rendering-stub' + +// eslint-disable-next-line import/no-extraneous-dependencies +import * as ReactServerDOMWebpackServerNode from 'react-server-dom-webpack/server.node' +// eslint-disable-next-line import/no-extraneous-dependencies +import * as ReactServerDOMWebpackServerEdge from 'react-server-dom-webpack/server.edge' + +export { + React, + ReactDOM, + ReactServerDOMWebpackServerNode, + ReactServerDOMWebpackServerEdge, +} diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/rsc/react-dom.ts b/packages/next/src/server/future/route-modules/app-page/vendored/rsc/react-dom.ts new file mode 100644 index 0000000000000..5d369d4e33771 --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/rsc/react-dom.ts @@ -0,0 +1 @@ +module.exports = require('../../module.compiled').vendored['react-rsc'].ReactDOM diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/rsc/react-server-dom-webpack-server-edge.ts b/packages/next/src/server/future/route-modules/app-page/vendored/rsc/react-server-dom-webpack-server-edge.ts new file mode 100644 index 0000000000000..0ae9701b1e912 --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/rsc/react-server-dom-webpack-server-edge.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'react-rsc' +].ReactServerDOMWebpackServerEdge diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/rsc/react-server-dom-webpack-server-node.ts b/packages/next/src/server/future/route-modules/app-page/vendored/rsc/react-server-dom-webpack-server-node.ts new file mode 100644 index 0000000000000..fbb7bd17d4ffc --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/rsc/react-server-dom-webpack-server-node.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'react-rsc' +].ReactServerDOMWebpackServerNode diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/rsc/react.ts b/packages/next/src/server/future/route-modules/app-page/vendored/rsc/react.ts new file mode 100644 index 0000000000000..41b44328775ab --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/rsc/react.ts @@ -0,0 +1 @@ +module.exports = require('../../module.compiled').vendored['react-rsc'].React diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/shared/entrypoints.ts b/packages/next/src/server/future/route-modules/app-page/vendored/shared/entrypoints.ts new file mode 100644 index 0000000000000..b5a1bf1a3fd02 --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/shared/entrypoints.ts @@ -0,0 +1,4 @@ +import * as ReactJsxDevRuntime from 'react/jsx-dev-runtime' +import * as ReactJsxRuntime from 'react/jsx-runtime' + +export { ReactJsxDevRuntime, ReactJsxRuntime } diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/shared/react-jsx-dev-runtime.ts b/packages/next/src/server/future/route-modules/app-page/vendored/shared/react-jsx-dev-runtime.ts new file mode 100644 index 0000000000000..9623bb4a90ae0 --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/shared/react-jsx-dev-runtime.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'react-shared' +].ReactJsxDevRuntime diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/shared/react-jsx-runtime.ts b/packages/next/src/server/future/route-modules/app-page/vendored/shared/react-jsx-runtime.ts new file mode 100644 index 0000000000000..b7d24f304f96b --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/shared/react-jsx-runtime.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'react-shared' +].ReactJsxRuntime diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/ssr/entrypoints.ts b/packages/next/src/server/future/route-modules/app-page/vendored/ssr/entrypoints.ts new file mode 100644 index 0000000000000..aa071a9567055 --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/ssr/entrypoints.ts @@ -0,0 +1,9 @@ +import * as React from 'react' +import * as ReactDOM from 'react-dom/server-rendering-stub' + +// eslint-disable-next-line import/no-extraneous-dependencies +import * as ReactDOMServerEdge from 'react-dom/server.edge' +// eslint-disable-next-line import/no-extraneous-dependencies +import * as ReactServerDOMWebpackClientEdge from 'react-server-dom-webpack/client.edge' + +export { React, ReactDOM, ReactDOMServerEdge, ReactServerDOMWebpackClientEdge } diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/ssr/react-dom-server-edge.ts b/packages/next/src/server/future/route-modules/app-page/vendored/ssr/react-dom-server-edge.ts new file mode 100644 index 0000000000000..0908aefd95554 --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/ssr/react-dom-server-edge.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'react-ssr' +].ReactDOMServerEdge diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/ssr/react-dom.ts b/packages/next/src/server/future/route-modules/app-page/vendored/ssr/react-dom.ts new file mode 100644 index 0000000000000..378577fa80ec2 --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/ssr/react-dom.ts @@ -0,0 +1 @@ +module.exports = require('../../module.compiled').vendored['react-ssr'].ReactDOM diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/ssr/react-server-dom-webpack-client-edge.ts b/packages/next/src/server/future/route-modules/app-page/vendored/ssr/react-server-dom-webpack-client-edge.ts new file mode 100644 index 0000000000000..5398d7eecc700 --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/ssr/react-server-dom-webpack-client-edge.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'react-ssr' +].ReactServerDOMWebpackClientEdge diff --git a/packages/next/src/server/future/route-modules/app-page/vendored/ssr/react.ts b/packages/next/src/server/future/route-modules/app-page/vendored/ssr/react.ts new file mode 100644 index 0000000000000..c2947601471d3 --- /dev/null +++ b/packages/next/src/server/future/route-modules/app-page/vendored/ssr/react.ts @@ -0,0 +1 @@ +module.exports = require('../../module.compiled').vendored['react-ssr'].React diff --git a/packages/next/src/server/future/route-modules/pages/module.ts b/packages/next/src/server/future/route-modules/pages/module.ts index e2730ef668901..3abbe1da064ec 100644 --- a/packages/next/src/server/future/route-modules/pages/module.ts +++ b/packages/next/src/server/future/route-modules/pages/module.ts @@ -18,7 +18,7 @@ import { type RouteModuleOptions, } from '../route-module' import { renderToHTMLImpl, renderToHTML } from '../../../render' -import * as sharedModules from './shared-modules' +import * as vendoredContexts from './vendored/contexts/entrypoints' /** * The userland module for a page. This is the module that is exported from the @@ -105,8 +105,6 @@ export class PagesRouteModule extends RouteModule< > { private readonly components: PagesComponents - static readonly sharedModules = sharedModules - constructor(options: PagesRouteModuleOptions) { super(options) @@ -132,7 +130,11 @@ export class PagesRouteModule extends RouteModule< } } +const vendored = { + contexts: vendoredContexts, +} + // needed for the static build -export { renderToHTML } +export { renderToHTML, vendored } export default PagesRouteModule diff --git a/packages/next/src/server/future/route-modules/pages/shared-modules.ts b/packages/next/src/server/future/route-modules/pages/shared-modules.ts deleted file mode 100644 index 55cdfbdeca37c..0000000000000 --- a/packages/next/src/server/future/route-modules/pages/shared-modules.ts +++ /dev/null @@ -1,12 +0,0 @@ -// the name of the export has to be the camelCase version of the file name (without the extension) -export * as htmlContext from '../../../../shared/lib/html-context.shared-runtime' -export * as routerContext from '../../../../shared/lib/router-context.shared-runtime' -export * as ampContext from '../../../../shared/lib/amp-context.shared-runtime' -export * as headManagerContext from '../../../../shared/lib/head-manager-context.shared-runtime' -export * as adapters from '../../../../shared/lib/router/adapters.shared-runtime' -export * as loadableContext from '../../../../shared/lib/loadable-context.shared-runtime' -export * as appRouterContext from '../../../../shared/lib/app-router-context.shared-runtime' -export * as hooksClientContext from '../../../../shared/lib/hooks-client-context.shared-runtime' -export * as imageConfigContext from '../../../../shared/lib/image-config-context.shared-runtime' -export * as runtimeConfig from '../../../../shared/lib/runtime-config.shared-runtime' -export * as loadable from '../../../../shared/lib/loadable.shared-runtime' diff --git a/packages/next/src/server/future/route-modules/pages/vendored/contexts/amp-context.ts b/packages/next/src/server/future/route-modules/pages/vendored/contexts/amp-context.ts new file mode 100644 index 0000000000000..474e4f387711e --- /dev/null +++ b/packages/next/src/server/future/route-modules/pages/vendored/contexts/amp-context.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].AmpContext diff --git a/packages/next/src/server/future/route-modules/pages/vendored/contexts/app-router-context.ts b/packages/next/src/server/future/route-modules/pages/vendored/contexts/app-router-context.ts new file mode 100644 index 0000000000000..a112b6b26738f --- /dev/null +++ b/packages/next/src/server/future/route-modules/pages/vendored/contexts/app-router-context.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].AppRouterContext diff --git a/packages/next/src/server/future/route-modules/pages/vendored/contexts/entrypoints.ts b/packages/next/src/server/future/route-modules/pages/vendored/contexts/entrypoints.ts new file mode 100644 index 0000000000000..3e244ec2d314e --- /dev/null +++ b/packages/next/src/server/future/route-modules/pages/vendored/contexts/entrypoints.ts @@ -0,0 +1,10 @@ +export * as RouterContext from '../../../../../../shared/lib/router-context.shared-runtime' +export * as LoadableContext from '../../../../../../shared/lib/loadable-context.shared-runtime' +export * as Loadable from '../../../../../../shared/lib/loadable.shared-runtime' +export * as ImageConfigContext from '../../../../../../shared/lib/image-config-context.shared-runtime' +export * as HtmlContext from '../../../../../../shared/lib/html-context.shared-runtime' +export * as HooksClientContext from '../../../../../../shared/lib/hooks-client-context.shared-runtime' +export * as HeadManagerContext from '../../../../../../shared/lib/head-manager-context.shared-runtime' +export * as AppRouterContext from '../../../../../../shared/lib/app-router-context.shared-runtime' +export * as AmpContext from '../../../../../../shared/lib/amp-context.shared-runtime' +export * as ServerInsertedHtml from '../../../../../../shared/lib/server-inserted-html.shared-runtime' diff --git a/packages/next/src/server/future/route-modules/pages/vendored/contexts/head-manager-context.ts b/packages/next/src/server/future/route-modules/pages/vendored/contexts/head-manager-context.ts new file mode 100644 index 0000000000000..b7f082e3339de --- /dev/null +++ b/packages/next/src/server/future/route-modules/pages/vendored/contexts/head-manager-context.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].HeadManagerContext diff --git a/packages/next/src/server/future/route-modules/pages/vendored/contexts/hooks-client-context.ts b/packages/next/src/server/future/route-modules/pages/vendored/contexts/hooks-client-context.ts new file mode 100644 index 0000000000000..29aa771033f15 --- /dev/null +++ b/packages/next/src/server/future/route-modules/pages/vendored/contexts/hooks-client-context.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].HooksClientContext diff --git a/packages/next/src/server/future/route-modules/pages/vendored/contexts/html-context.ts b/packages/next/src/server/future/route-modules/pages/vendored/contexts/html-context.ts new file mode 100644 index 0000000000000..ae1126abb6f99 --- /dev/null +++ b/packages/next/src/server/future/route-modules/pages/vendored/contexts/html-context.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].HtmlContext diff --git a/packages/next/src/server/future/route-modules/pages/vendored/contexts/image-config-context.ts b/packages/next/src/server/future/route-modules/pages/vendored/contexts/image-config-context.ts new file mode 100644 index 0000000000000..3537107ae9982 --- /dev/null +++ b/packages/next/src/server/future/route-modules/pages/vendored/contexts/image-config-context.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].ImageConfigContext diff --git a/packages/next/src/server/future/route-modules/pages/vendored/contexts/loadable-context.ts b/packages/next/src/server/future/route-modules/pages/vendored/contexts/loadable-context.ts new file mode 100644 index 0000000000000..de9e07464c6fb --- /dev/null +++ b/packages/next/src/server/future/route-modules/pages/vendored/contexts/loadable-context.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].LoadableContext diff --git a/packages/next/src/server/future/route-modules/pages/vendored/contexts/loadable.ts b/packages/next/src/server/future/route-modules/pages/vendored/contexts/loadable.ts new file mode 100644 index 0000000000000..f67d05a251655 --- /dev/null +++ b/packages/next/src/server/future/route-modules/pages/vendored/contexts/loadable.ts @@ -0,0 +1 @@ +module.exports = require('../../module.compiled').vendored['contexts'].Loadable diff --git a/packages/next/src/server/future/route-modules/pages/vendored/contexts/router-context.ts b/packages/next/src/server/future/route-modules/pages/vendored/contexts/router-context.ts new file mode 100644 index 0000000000000..5a2f92e05309e --- /dev/null +++ b/packages/next/src/server/future/route-modules/pages/vendored/contexts/router-context.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].RouterContext diff --git a/packages/next/src/server/future/route-modules/pages/vendored/contexts/server-inserted-html.ts b/packages/next/src/server/future/route-modules/pages/vendored/contexts/server-inserted-html.ts new file mode 100644 index 0000000000000..3c488b0db8ee3 --- /dev/null +++ b/packages/next/src/server/future/route-modules/pages/vendored/contexts/server-inserted-html.ts @@ -0,0 +1,3 @@ +module.exports = require('../../module.compiled').vendored[ + 'contexts' +].ServerInsertedHtml diff --git a/packages/next/src/server/import-overrides.ts b/packages/next/src/server/import-overrides.ts index 831609c866548..c72f42612eae3 100644 --- a/packages/next/src/server/import-overrides.ts +++ b/packages/next/src/server/import-overrides.ts @@ -23,57 +23,6 @@ export const defaultOverrides = { : resolve('styled-jsx/style', nextPaths), } -export const baseOverrides = { - react: 'next/dist/compiled/react', - 'react/package.json': 'next/dist/compiled/react/package.json', - 'react/jsx-runtime': 'next/dist/compiled/react/jsx-runtime', - 'react/jsx-dev-runtime': 'next/dist/compiled/react/jsx-dev-runtime', - 'react-dom': 'next/dist/compiled/react-dom/server-rendering-stub', - 'react-dom/package.json': 'next/dist/compiled/react-dom/package.json', - 'react-dom/client': 'next/dist/compiled/react-dom/client', - 'react-dom/server': 'next/dist/compiled/react-dom/server', - // when the require hook applies, we want to use the edge version, for both app and pages - 'react-dom/server.browser': 'next/dist/compiled/react-dom/server.edge', - 'react-dom/server.edge': 'next/dist/compiled/react-dom/server.edge', - 'react-server-dom-webpack/client': - 'next/dist/compiled/react-server-dom-webpack/client', - 'react-server-dom-webpack/client.edge': - 'next/dist/compiled/react-server-dom-webpack/client.edge', - 'react-server-dom-webpack/server.edge': - 'next/dist/compiled/react-server-dom-webpack/server.edge', - 'react-server-dom-webpack/server.node': - 'next/dist/compiled/react-server-dom-webpack/server.node', -} - -export const experimentalOverrides = { - react: 'next/dist/compiled/react-experimental', - 'react/jsx-runtime': 'next/dist/compiled/react-experimental/jsx-runtime', - 'react/jsx-dev-runtime': - 'next/dist/compiled/react-experimental/jsx-dev-runtime', - 'react-dom': - 'next/dist/compiled/react-dom-experimental/server-rendering-stub', - 'react/package.json': 'next/dist/compiled/react-experimental/package.json', - 'react-dom/package.json': - 'next/dist/compiled/react-dom-experimental/package.json', - 'react-dom/client': 'next/dist/compiled/react-dom-experimental/client', - 'react-dom/server': 'next/dist/compiled/react-dom-experimental/server', - // when the require hook applies, we want to use the edge version, for both app and pages - 'react-dom/server.browser': - 'next/dist/compiled/react-dom-experimental/server.edge', - 'react-dom/server.edge': - 'next/dist/compiled/react-dom-experimental/server.edge', - 'react-server-dom-webpack/client': - 'next/dist/compiled/react-server-dom-webpack-experimental/client', - 'react-server-dom-webpack/client.edge': - 'next/dist/compiled/react-server-dom-webpack-experimental/client.edge', - 'react-server-dom-webpack/server.edge': - 'next/dist/compiled/react-server-dom-webpack-experimental/server.edge', - 'react-server-dom-webpack/server.node': - 'next/dist/compiled/react-server-dom-webpack-experimental/server.node', -} - -let aliasedPrebundledReact = false - const toResolveMap = (map: Record): [string, string][] => Object.entries(map).map(([key, value]) => [key, resolve(value, nextPaths)]) @@ -84,20 +33,3 @@ export function addHookAliases(aliases: [string, string][] = []) { } addHookAliases(toResolveMap(defaultOverrides)) - -// Override built-in React packages if necessary -export function overrideReact() { - if (process.env.__NEXT_PRIVATE_PREBUNDLED_REACT && !aliasedPrebundledReact) { - aliasedPrebundledReact = true - - // Require these modules with static paths to make sure they are tracked by - // NFT when building the app in standalone mode, as we are now conditionally - // aliasing them it's tricky to track them in build time. - if (process.env.__NEXT_PRIVATE_PREBUNDLED_REACT === 'experimental') { - addHookAliases(toResolveMap(experimentalOverrides)) - } else { - addHookAliases(toResolveMap(baseOverrides)) - } - } -} -overrideReact() diff --git a/packages/next/src/server/lib/router-utils/setup-dev.ts b/packages/next/src/server/lib/router-utils/setup-dev.ts index c1777d1312aa8..8db318f8b2037 100644 --- a/packages/next/src/server/lib/router-utils/setup-dev.ts +++ b/packages/next/src/server/lib/router-utils/setup-dev.ts @@ -1729,6 +1729,7 @@ async function startWatcher(opts: SetupOpts) { isNodeServer, middlewareMatchers: undefined, previewModeId: undefined, + useServerActions: !!nextConfig.experimental.serverActions, }) Object.keys(plugin.definitions).forEach((key) => { diff --git a/packages/next/src/server/render.tsx b/packages/next/src/server/render.tsx index 228ed9172227e..7df9637d22775 100644 --- a/packages/next/src/server/render.tsx +++ b/packages/next/src/server/render.tsx @@ -91,7 +91,7 @@ import { adaptForAppRouterInstance, adaptForSearchParams, PathnameContextProviderAdapter, -} from '../shared/lib/router/adapters.shared-runtime' +} from '../shared/lib/router/adapters' import { AppRouterContext } from '../shared/lib/app-router-context.shared-runtime' import { SearchParamsContext } from '../shared/lib/hooks-client-context.shared-runtime' import { getTracer } from './lib/trace/tracer' diff --git a/packages/next/src/server/require-hook.js b/packages/next/src/server/require-hook.js index ce9e30e6e9ffe..6e6c89ffc3555 100644 --- a/packages/next/src/server/require-hook.js +++ b/packages/next/src/server/require-hook.js @@ -8,7 +8,8 @@ const mod = require('module') const originalRequire = mod.prototype.require const resolveFilename = mod._resolveFilename -const { overrideReact, hookPropertyMap } = require('./import-overrides') +const { hookPropertyMap } = require('./import-overrides') +const { PHASE_PRODUCTION_BUILD } = require('../shared/lib/constants') mod._resolveFilename = function ( originalResolveFilename, @@ -18,9 +19,6 @@ mod._resolveFilename = function ( isMain, options ) { - // In case the environment variable is set after the module is loaded. - overrideReact() - const hookResolved = requestMap.get(request) if (hookResolved) request = hookResolved @@ -32,21 +30,20 @@ mod._resolveFilename = function ( // This is a hack to make sure that if a user requires a Next.js module that wasn't bundled // that needs to point to the rendering runtime version, it will point to the correct one. // This can happen on `pages` when a user requires a dependency that uses next/image for example. -// This is only needed in production as in development we fallback to the external version. -if (process.env.NODE_ENV !== 'development' && !process.env.TURBOPACK) { - mod.prototype.require = function (request) { - if (request.endsWith('.shared-runtime')) { - const isAppRequire = process.env.__NEXT_PRIVATE_RUNTIME_TYPE === 'app' - const currentRuntime = `${ - isAppRequire - ? 'next/dist/compiled/next-server/app-page.runtime' - : 'next/dist/compiled/next-server/pages.runtime' - }.prod` - const base = path.basename(request, '.shared-runtime') - const camelized = base.replace(/-([a-z])/g, (g) => g[1].toUpperCase()) - const instance = originalRequire.call(this, currentRuntime) - return instance.default.sharedModules[camelized] - } - return originalRequire.call(this, request) +mod.prototype.require = function (request) { + if ( + (process.env.NEXT_PHASE !== PHASE_PRODUCTION_BUILD || + process.env.NEXT_IS_EXPORT_WORKER) && + request.endsWith('.shared-runtime') + ) { + return originalRequire.call( + this, + `next/dist/server/future/route-modules/pages/vendored/contexts/${path.basename( + request, + '.shared-runtime' + )}` + ) } + + return originalRequire.call(this, request) } diff --git a/packages/next/src/shared/lib/router/adapters.test.tsx b/packages/next/src/shared/lib/router/adapters.test.tsx index e47ce2174dd35..fa8e48f2fc088 100644 --- a/packages/next/src/shared/lib/router/adapters.test.tsx +++ b/packages/next/src/shared/lib/router/adapters.test.tsx @@ -1,4 +1,4 @@ -import { adaptForAppRouterInstance } from './adapters.shared-runtime' +import { adaptForAppRouterInstance } from './adapters' import { NextRouter } from './router' describe('adaptForAppRouterInstance', () => { diff --git a/packages/next/src/shared/lib/router/adapters.shared-runtime.tsx b/packages/next/src/shared/lib/router/adapters.tsx similarity index 100% rename from packages/next/src/shared/lib/router/adapters.shared-runtime.tsx rename to packages/next/src/shared/lib/router/adapters.tsx diff --git a/packages/next/src/shared/lib/runtime-config.shared-runtime.ts b/packages/next/src/shared/lib/runtime-config.external.ts similarity index 100% rename from packages/next/src/shared/lib/runtime-config.shared-runtime.ts rename to packages/next/src/shared/lib/runtime-config.external.ts diff --git a/packages/next/taskfile.js b/packages/next/taskfile.js index 476118fe16f17..30b28b90a9f48 100644 --- a/packages/next/taskfile.js +++ b/packages/next/taskfile.js @@ -2683,38 +2683,137 @@ export async function release(task) { await task.clear('dist').start('build') } -export async function next_bundle_prod(task, opts) { +export async function next_bundle_app_turbo(task, opts) { + await task.source('dist').webpack({ + watch: opts.dev, + config: require('./webpack.config')({ + turbo: true, + bundleType: 'app', + }), + name: 'next-bundle-app-turbo', + }) +} + +export async function next_bundle_app_prod(task, opts) { await task.source('dist').webpack({ watch: opts.dev, config: require('./webpack.config')({ dev: false, + bundleType: 'app', }), - name: 'next-bundle-prod', + name: 'next-bundle-app-prod', }) } -export async function next_bundle_dev(task, opts) { +export async function next_bundle_app_dev(task, opts) { await task.source('dist').webpack({ watch: opts.dev, config: require('./webpack.config')({ dev: true, + bundleType: 'app', }), - name: 'next-bundle-dev', + name: 'next-bundle-app-dev', }) } -export async function next_bundle_turbo_prod(task, opts) { +export async function next_bundle_app_turbo_experimental(task, opts) { await task.source('dist').webpack({ watch: opts.dev, config: require('./webpack.config')({ turbo: true, + bundleType: 'app', + experimental: true, + }), + name: 'next-bundle-app-turbo-experimental', + }) +} + +export async function next_bundle_app_prod_experimental(task, opts) { + await task.source('dist').webpack({ + watch: opts.dev, + config: require('./webpack.config')({ + dev: false, + bundleType: 'app', + experimental: true, }), - name: 'next-bundle-prod-turbo', + name: 'next-bundle-app-prod-experimental', }) } + +export async function next_bundle_app_dev_experimental(task, opts) { + await task.source('dist').webpack({ + watch: opts.dev, + config: require('./webpack.config')({ + dev: true, + bundleType: 'app', + experimental: true, + }), + name: 'next-bundle-app-dev-experimental', + }) +} + +export async function next_bundle_pages_prod(task, opts) { + await task.source('dist').webpack({ + watch: opts.dev, + config: require('./webpack.config')({ + dev: false, + bundleType: 'pages', + }), + name: 'next-bundle-pages-prod', + }) +} + +export async function next_bundle_pages_dev(task, opts) { + await task.source('dist').webpack({ + watch: opts.dev, + config: require('./webpack.config')({ + dev: true, + bundleType: 'pages', + }), + name: 'next-bundle-pages-dev', + }) +} + +export async function next_bundle_pages_turbo(task, opts) { + await task.source('dist').webpack({ + watch: opts.dev, + config: require('./webpack.config')({ + turbo: true, + bundleType: 'pages', + }), + name: 'next-bundle-pages-turbo', + }) +} + +export async function next_bundle_server(task, opts) { + await task.source('dist').webpack({ + watch: opts.dev, + config: require('./webpack.config')({ + dev: false, + bundleType: 'server', + }), + name: 'next-bundle-server', + }) +} + export async function next_bundle(task, opts) { await task.parallel( - ['next_bundle_prod', 'next_bundle_dev', 'next_bundle_turbo_prod'], + [ + // builds the app (route/page) bundles + 'next_bundle_app_turbo', + 'next_bundle_app_prod', + 'next_bundle_app_dev', + // builds the app (route/page) bundles with react experimental + 'next_bundle_app_turbo_experimental', + 'next_bundle_app_prod_experimental', + 'next_bundle_app_dev_experimental', + // builds the pages (page/api) bundles + 'next_bundle_pages_prod', + 'next_bundle_pages_dev', + 'next_bundle_pages_turbo', + // builds the minimal server + 'next_bundle_server', + ], opts ) } diff --git a/packages/next/types/misc.d.ts b/packages/next/types/misc.d.ts index b22d2bd2957ee..e98312232711d 100644 --- a/packages/next/types/misc.d.ts +++ b/packages/next/types/misc.d.ts @@ -20,8 +20,13 @@ declare module 'next/dist/compiled/react-dom/server' declare module 'next/dist/compiled/react-dom/server.edge' declare module 'next/dist/compiled/react-dom/server.browser' declare module 'next/dist/compiled/browserslist' + declare module 'react-server-dom-webpack/client' declare module 'react-server-dom-webpack/server.edge' +declare module 'react-server-dom-webpack/server.node' +declare module 'react-server-dom-webpack/client.edge' + +declare module 'react-dom/server-rendering-stub' declare module 'react-dom/server.browser' declare module 'react-dom/server.edge' diff --git a/packages/next/webpack.config.js b/packages/next/webpack.config.js index 83fe9d3009877..d03ff0cfb52ec 100644 --- a/packages/next/webpack.config.js +++ b/packages/next/webpack.config.js @@ -3,7 +3,7 @@ const path = require('path') const TerserPlugin = require('terser-webpack-plugin') const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer') -const minimalExternals = [ +const pagesExternals = [ 'react', 'react/package.json', 'react/jsx-runtime', @@ -18,6 +18,33 @@ const minimalExternals = [ 'react-server-dom-webpack/client.edge', 'react-server-dom-webpack/server.edge', 'react-server-dom-webpack/server.node', +] + +function makeAppAliases(reactChannel = '') { + const alias = { + react$: `next/dist/compiled/react${reactChannel}`, + 'react/shared-subset$': `next/dist/compiled/react${reactChannel}/react.shared-subset`, + 'react-dom/server-rendering-stub$': `next/dist/compiled/react-dom${reactChannel}/server-rendering-stub`, + 'react-dom$': `next/dist/compiled/react-dom${reactChannel}/server-rendering-stub`, + 'react/jsx-runtime$': `next/dist/compiled/react${reactChannel}/jsx-runtime`, + 'react/jsx-dev-runtime$': `next/dist/compiled/react${reactChannel}/jsx-dev-runtime`, + 'react-dom/client$': `next/dist/compiled/react-dom${reactChannel}/client`, + 'react-dom/server$': `next/dist/compiled/react-dom${reactChannel}/server`, + 'react-dom/server.edge$': `next/dist/compiled/react-dom${reactChannel}/server.edge`, + 'react-dom/server.browser$': `next/dist/compiled/react-dom${reactChannel}/server.browser`, + 'react-server-dom-webpack/client$': `next/dist/compiled/react-server-dom-webpack${reactChannel}/client`, + 'react-server-dom-webpack/client.edge$': `next/dist/compiled/react-server-dom-webpack${reactChannel}/client.edge`, + 'react-server-dom-webpack/server.edge$': `next/dist/compiled/react-server-dom-webpack${reactChannel}/server.edge`, + 'react-server-dom-webpack/server.node$': `next/dist/compiled/react-server-dom-webpack${reactChannel}/server.node`, + } + + return alias +} + +const appAliases = makeAppAliases() +const appExperimentalAliases = makeAppAliases('-experimental') + +const sharedExternals = [ 'styled-jsx', 'styled-jsx/style', '@opentelemetry/api', @@ -44,13 +71,36 @@ const externalsRegexMap = { '(.*)trace/tracer$': 'next/dist/server/lib/trace/tracer', } -module.exports = ({ dev, turbo }) => { +const bundleTypes = { + app: { + 'app-page': path.join( + __dirname, + 'dist/esm/server/future/route-modules/app-page/module.js' + ), + 'app-route': path.join( + __dirname, + 'dist/esm/server/future/route-modules/app-route/module.js' + ), + }, + pages: { + pages: path.join( + __dirname, + 'dist/esm/server/future/route-modules/pages/module.js' + ), + 'pages-api': path.join( + __dirname, + 'dist/esm/server/future/route-modules/pages-api/module.js' + ), + }, + server: { + server: path.join(__dirname, 'dist/esm/server/next-server.js'), + }, +} + +module.exports = ({ dev, turbo, bundleType, experimental }) => { const externalHandler = ({ context, request, getResolve }, callback) => { ;(async () => { - if ( - ((dev || turbo) && request.endsWith('.shared-runtime')) || - request.endsWith('.external') - ) { + if (request.endsWith('.external')) { const resolve = getResolve() const resolved = await resolve(context, request) const relative = path.relative( @@ -72,32 +122,14 @@ module.exports = ({ dev, turbo }) => { /** @type {webpack.Configuration} */ return { - entry: { - server: path.join(__dirname, 'dist/esm/server/next-server.js'), - 'app-page': path.join( - __dirname, - 'dist/esm/server/future/route-modules/app-page/module.js' - ), - 'app-route': path.join( - __dirname, - 'dist/esm/server/future/route-modules/app-route/module.js' - ), - pages: path.join( - __dirname, - 'dist/esm/server/future/route-modules/pages/module.js' - ), - 'pages-api': path.join( - __dirname, - 'dist/esm/server/future/route-modules/pages-api/module.js' - ), - }, + entry: bundleTypes[bundleType], target: 'node', mode: 'production', output: { path: path.join(__dirname, 'dist/compiled/next-server'), - filename: `[name]${turbo ? '-turbo' : ''}.runtime.${ - dev ? 'dev' : 'prod' - }.js`, + filename: `[name]${turbo ? '-turbo' : ''}${ + experimental ? '-experimental' : '' + }.runtime.${dev ? 'dev' : 'prod'}.js`, libraryTarget: 'commonjs2', }, optimization: { @@ -123,6 +155,7 @@ module.exports = ({ dev, turbo }) => { }, plugins: [ new webpack.DefinePlugin({ + 'typeof window': JSON.stringify('undefined'), 'process.env.NEXT_MINIMAL': JSON.stringify('true'), 'this.serverOptions.experimentalTestProxy': JSON.stringify(false), 'this.minimalMode': JSON.stringify(true), @@ -135,12 +168,81 @@ module.exports = ({ dev, turbo }) => { }), !!process.env.ANALYZE && new BundleAnalyzerPlugin({ - analyzerPort: 8888 + (dev ? 0 : 1) + (turbo ? 1 : 0), + analyzerPort: calculateUniquePort( + dev, + turbo, + experimental, + bundleType + ), + openAnalyzer: false, }), ].filter(Boolean), stats: { optimizationBailout: true, }, - externals: [...minimalExternals, externalsMap, externalHandler], + resolve: { + alias: + bundleType === 'app' + ? experimental + ? appExperimentalAliases + : appAliases + : {}, + }, + module: { + rules: [ + { + include: /vendored\/rsc\/entrypoints/, + resolve: { + conditionNames: ['react-server', '...'], + alias: { + react$: `next/dist/compiled/react${ + experimental ? '-experimental' : '' + }/react.shared-subset`, + }, + }, + layer: 'react-server', + }, + { + issuerLayer: 'react-server', + resolve: { + conditionNames: ['react-server', '...'], + alias: { + react$: `next/dist/compiled/react${ + experimental ? '-experimental' : '' + }/react.shared-subset`, + }, + }, + }, + ], + }, + externals: [ + ...sharedExternals, + ...(bundleType === 'pages' ? pagesExternals : []), + externalsMap, + externalHandler, + ], + experiments: { + layers: true, + }, } } + +function calculateUniquePort(dev, turbo, experimental, bundleType) { + const devOffset = dev ? 1000 : 0 + const turboOffset = turbo ? 200 : 0 + const experimentalOffset = experimental ? 40 : 0 + let bundleTypeOffset + + switch (bundleType) { + case 'app': + bundleTypeOffset = 1 + break + case 'pages': + bundleTypeOffset = 2 + break + default: + bundleTypeOffset = 3 + } + + return 8888 + devOffset + turboOffset + experimentalOffset + bundleTypeOffset +} diff --git a/test/e2e/app-dir/rsc-basic/app/app-react/client-react.js b/test/e2e/app-dir/rsc-basic/app/app-react/client-react.js index 1220ff4c1154c..2e5f208139730 100644 --- a/test/e2e/app-dir/rsc-basic/app/app-react/client-react.js +++ b/test/e2e/app-dir/rsc-basic/app/app-react/client-react.js @@ -2,7 +2,7 @@ import React from 'react' import ReactDOM from 'react-dom' -import ReactDOMServer from 'react-dom/server' +import ReactDOMServer from 'react-dom/server.edge' export default function ClientReact() { return ( diff --git a/test/e2e/app-dir/rsc-basic/rsc-basic.test.ts b/test/e2e/app-dir/rsc-basic/rsc-basic.test.ts index 4a0ebc87638e7..a79048bbc94f1 100644 --- a/test/e2e/app-dir/rsc-basic/rsc-basic.test.ts +++ b/test/e2e/app-dir/rsc-basic/rsc-basic.test.ts @@ -456,7 +456,7 @@ createNextDescribe( expect(await res.text()).toBe('Hello from import-test.js') }) - it('should use bundled react for pages with app', async () => { + it('should not use bundled react for pages with app', async () => { const ssrPaths = ['/pages-react', '/edge-pages-react'] const promises = ssrPaths.map(async (pathname) => { const resPages$ = await next.render$(pathname) @@ -467,7 +467,7 @@ createNextDescribe( ] ssrPagesReactVersions.forEach((version) => { - expect(version).toMatch('-canary-') + expect(version).not.toMatch('-canary-') }) }) await Promise.all(promises) @@ -502,10 +502,10 @@ createNextDescribe( `) browserPagesReactVersions.forEach((version) => - expect(version).toMatch('-canary-') + expect(version).not.toMatch('-canary-') ) browserEdgePagesReactVersions.forEach((version) => - expect(version).toMatch('-canary-') + expect(version).not.toMatch('-canary-') ) }) diff --git a/test/production/custom-server/custom-server.test.ts b/test/production/custom-server/custom-server.test.ts index cb643e015b545..d3514ee0c167a 100644 --- a/test/production/custom-server/custom-server.test.ts +++ b/test/production/custom-server/custom-server.test.ts @@ -21,10 +21,10 @@ createNextDescribe( expect($('body').text()).toMatch(/app: .+-canary/) }) - it('should render pages with react canary', async () => { + it('should not render pages with react canary', async () => { const $ = await next.render$(`/2`) expect($('body').text()).toMatch(/pages:/) - expect($('body').text()).toMatch(/canary/) + expect($('body').text()).not.toMatch(/canary/) }) }) }