diff --git a/packages/next-swc/crates/next-core/src/next_config.rs b/packages/next-swc/crates/next-core/src/next_config.rs index 51e4ad642b7b9..98957aae33d32 100644 --- a/packages/next-swc/crates/next-core/src/next_config.rs +++ b/packages/next-swc/crates/next-core/src/next_config.rs @@ -73,6 +73,7 @@ pub struct NextConfig { pub experimental: ExperimentalConfig, pub images: ImageConfig, pub page_extensions: Vec, + pub react_production_profiling: Option, pub react_strict_mode: Option, pub transpile_packages: Option>, pub modularize_imports: Option>, @@ -789,6 +790,11 @@ impl NextConfig { Vc::cell(self.bundle_pages_router_dependencies.unwrap_or_default()) } + #[turbo_tasks::function] + pub fn enable_react_production_profiling(&self) -> Vc { + Vc::cell(self.react_production_profiling.unwrap_or_default()) + } + #[turbo_tasks::function] pub async fn server_external_packages(self: Vc) -> Result>> { Ok(Vc::cell( 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 5044ccee27b11..11c4ff0302a41 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 @@ -169,6 +169,14 @@ pub async fn get_next_client_import_map( "next/dist/compiled/react-dom-experimental/static.browser", ), ); + let react_client_package = get_react_client_package(&next_config).await?; + import_map.insert_exact_alias( + "react-dom/client", + request_to_import_mapping( + app_dir, + &format!("next/dist/compiled/react-dom{react_flavor}/{react_client_package}"), + ), + ); import_map.insert_wildcard_alias( "react-dom/", request_to_import_mapping( @@ -322,6 +330,7 @@ pub async fn get_next_server_import_map( import_map.insert_exact_alias("react", external); import_map.insert_wildcard_alias("react/", external); import_map.insert_exact_alias("react-dom", external); + import_map.insert_exact_alias("react-dom/client", external); import_map.insert_wildcard_alias("react-dom/", external); import_map.insert_exact_alias("styled-jsx", external); import_map.insert_exact_alias( @@ -639,6 +648,17 @@ async fn insert_next_server_special_aliases( Ok(()) } +async fn get_react_client_package(&next_config: &Vc) -> Result<&'static str> { + let react_production_profiling = *next_config.enable_react_production_profiling().await?; + let react_client_package = if react_production_profiling { + "profiling" + } else { + "client" + }; + + Ok(react_client_package) +} + async fn rsc_aliases( import_map: &mut ImportMap, project_path: Vc, @@ -649,6 +669,7 @@ async fn rsc_aliases( let ppr = *next_config.enable_ppr().await?; let taint = *next_config.enable_taint().await?; let react_channel = if ppr || taint { "-experimental" } else { "" }; + let react_client_package = get_react_client_package(&next_config).await?; let mut alias = IndexMap::new(); if matches!( @@ -663,7 +684,7 @@ async fn rsc_aliases( "react/jsx-runtime" => format!("next/dist/compiled/react{react_channel}/jsx-runtime"), "react/jsx-dev-runtime" => format!("next/dist/compiled/react{react_channel}/jsx-dev-runtime"), "react/compiler-runtime" => format!("next/dist/compiled/react{react_channel}/compiler-runtime"), - "react-dom/client" => format!("next/dist/compiled/react-dom{react_channel}/client"), + "react-dom/client" => format!("next/dist/compiled/react-dom{react_channel}/{react_client_package}"), "react-dom/static" => format!("next/dist/compiled/react-dom-experimental/static"), "react-dom/static.edge" => format!("next/dist/compiled/react-dom-experimental/static.edge"), "react-dom/static.browser" => format!("next/dist/compiled/react-dom-experimental/static.browser"), @@ -841,6 +862,11 @@ async fn insert_next_shared_aliases( import_map.insert_singleton_alias("next", project_path); import_map.insert_singleton_alias("react", project_path); import_map.insert_singleton_alias("react-dom", project_path); + let react_client_package = get_react_client_package(&next_config).await?; + import_map.insert_exact_alias( + "react-dom/client", + request_to_import_mapping(project_path, &format!("react-dom/{react_client_package}")), + ); import_map.insert_alias( // Make sure you can't import custom server as it'll cause all Next.js internals to be diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts index fe356258db50b..940600cf6234d 100644 --- a/packages/next/src/build/index.ts +++ b/packages/next/src/build/index.ts @@ -697,6 +697,7 @@ export default async function build( loadConfig(PHASE_PRODUCTION_BUILD, dir, { // Log for next.config loading process silent: false, + reactProductionProfiling, }), turborepoAccessTraceResult ) diff --git a/packages/next/src/lib/turbopack-warning.ts b/packages/next/src/lib/turbopack-warning.ts index 29eb87b71124b..05a1368dd9512 100644 --- a/packages/next/src/lib/turbopack-warning.ts +++ b/packages/next/src/lib/turbopack-warning.ts @@ -50,10 +50,9 @@ const unsupportedTurbopackNextConfigOptions = [ ] // The following will need to be supported by `next build --turbo` -const unsupportedProductionSpecificTurbopackNextConfigOptions = [ +const unsupportedProductionSpecificTurbopackNextConfigOptions: string[] = [ // TODO: Support disabling sourcemaps, currently they're always enabled. // 'productionBrowserSourceMaps', - 'reactProductionProfiling', ] // check for babelrc, swc plugins diff --git a/packages/next/src/server/config.ts b/packages/next/src/server/config.ts index 2d2b1876615a1..26a01aee2affd 100644 --- a/packages/next/src/server/config.ts +++ b/packages/next/src/server/config.ts @@ -923,11 +923,13 @@ export default async function loadConfig( rawConfig, silent = true, onLoadUserConfig, + reactProductionProfiling, }: { customConfig?: object | null rawConfig?: boolean silent?: boolean onLoadUserConfig?: (conf: NextConfig) => void + reactProductionProfiling?: boolean } = {} ): Promise { if (!process.env.__NEXT_PRIVATE_RENDER_WORKER) { @@ -1084,6 +1086,10 @@ export default async function loadConfig( : canonicalBase) || '' } + if (reactProductionProfiling) { + userConfig.reactProductionProfiling = reactProductionProfiling + } + if ( userConfig.experimental?.turbo?.loaders && !userConfig.experimental?.turbo?.rules diff --git a/test/turbopack-build-tests-manifest.json b/test/turbopack-build-tests-manifest.json index 101b0b0fb8454..f7b9b03d85479 100644 --- a/test/turbopack-build-tests-manifest.json +++ b/test/turbopack-build-tests-manifest.json @@ -14107,13 +14107,12 @@ }, "test/integration/react-profiling-mode/test/index.test.js": { "passed": [ - "React Profiling Mode production mode without config enabled should not have used the react-dom profiling bundle" - ], - "failed": [ + "React Profiling Mode production mode without config enabled should not have used the react-dom profiling bundle", "React Profiling Mode production mode with config enabled should have used the react-dom profiling bundle for client component", "React Profiling Mode production mode with config enabled should have used the react-dom profiling bundle for pages", "React Profiling Mode production mode with config enabled should have used the react-dom profiling bundle for server component" ], + "failed": [], "pending": [], "flakey": [], "runtimeError": false