Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions crates/next-api/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use turbopack_core::{
asset::AssetContent,
chunk::{
ChunkGroupResult, ChunkingContext, ChunkingContextExt, EvaluatableAsset, EvaluatableAssets,
availability_info::AvailabilityInfo,
HmrChunkListSource, availability_info::AvailabilityInfo,
},
file_source::FileSource,
ident::{AssetIdent, Layer},
Expand Down Expand Up @@ -1434,7 +1434,11 @@ impl AppEndpoint {
let client_reference_chunks =
get_client_references_chunks_for_hmr(*client_references_chunks);
client_chunking_context
.hmr_chunk_list(client_components_chunks_ident, client_reference_chunks)
.hmr_chunk_list(
client_components_chunks_ident,
client_reference_chunks,
HmrChunkListSource::Entry,
)
.await?
.iter()
.copied()
Expand Down
17 changes: 17 additions & 0 deletions crates/next-api/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ use turbopack_core::{
NotFoundVersion, OptionVersionedContent, Update, Version, VersionState, VersionedContent,
},
};
use turbopack_ecmascript::async_chunk::proxy::{
activation_key_from_chunk_path, lazy_compilation_state,
};
#[cfg(all(feature = "process_pool", not(target_family = "wasm")))]
use turbopack_node::child_process_backend;
use turbopack_node::execution_context::ExecutionContext;
Expand Down Expand Up @@ -456,6 +459,17 @@ fn project_operation(project: ResolvedVc<ProjectContainer>) -> Vc<Project> {
project.project()
}

/// Activates the lazy dynamic import that `chunk_path` names, returning whether it named one. The
/// caller has to rebuild the owning entrypoint before serving the request.
#[turbo_tasks::function(operation, root)]
pub async fn activate_lazy_chunk_operation(chunk_path: RcStr) -> Result<Vc<bool>> {
let Some(key) = activation_key_from_chunk_path(&chunk_path) else {
return Ok(Vc::cell(false));
};
lazy_compilation_state(key).await?.activate();
Ok(Vc::cell(true))
}

#[turbo_tasks::function(operation, root)]
fn project_fs_operation(project: ResolvedVc<Project>) -> Vc<DiskFileSystem> {
project.project_fs()
Expand Down Expand Up @@ -1599,6 +1613,9 @@ impl Project {
.turbo_nested_async_chunking(self.next_mode(), true),
shared_runtime: self.next_config().turbo_shared_runtime(self.next_mode()),
per_page_module_graph: self.per_page_module_graph(),
lazy_dynamic_imports: self
.next_config()
.turbopack_lazy_dynamic_imports(*self.next_mode().await?),
debug_ids: self.next_config().turbopack_debug_ids(),
worker_asset_prefix: self.next_config().turbopack_worker_asset_prefix(),
should_use_absolute_url_references: self.next_config().inline_css(),
Expand Down
11 changes: 10 additions & 1 deletion crates/next-core/src/next_client/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,9 @@ pub async fn get_client_module_options_context(
mangle_export_names: *next_config.turbopack_mangle_export_names(mode).await?,
cjs_scope_hoisting: *next_config.turbopack_cjs_scope_hoisting().await?,
cross_module_constants: *next_config.turbopack_cross_module_constants().await?,
lazy_compilation: *next_config
.turbopack_lazy_dynamic_imports(*next_mode)
.await?,
preset_env_config,
..Default::default()
},
Expand Down Expand Up @@ -411,6 +414,7 @@ pub async fn get_client_module_options_context(
enable_typeof_window_inlining: None,
// Ignore e.g. import(`${url}`) requests in node_modules.
ignore_dynamic_requests: true,
lazy_compilation: false,
// Don't inject core-js polyfills into node_modules — only user code
// should be processed by preset_env's usage/entry mode.
preset_env_config: None,
Expand All @@ -433,6 +437,7 @@ pub async fn get_client_module_options_context(
enable_jsx: Some(JsxTransformOptions::default().resolved_cell()),
// Don't inject core-js polyfills into framework internals.
preset_env_config: None,
lazy_compilation: false,
..module_options_context.ecmascript.clone()
},
enable_postcss_transform: None,
Expand Down Expand Up @@ -492,6 +497,7 @@ pub struct ClientChunkingContextOptions {
pub nested_async_chunking: Vc<bool>,
pub shared_runtime: Vc<bool>,
pub per_page_module_graph: Vc<bool>,
pub lazy_dynamic_imports: Vc<bool>,
pub debug_ids: Vc<bool>,
pub worker_asset_prefix: Vc<Option<RcStr>>,
pub should_use_absolute_url_references: Vc<bool>,
Expand Down Expand Up @@ -541,6 +547,7 @@ pub async fn get_client_chunking_context(
nested_async_chunking,
shared_runtime,
per_page_module_graph,
lazy_dynamic_imports,
debug_ids,
worker_asset_prefix,
should_use_absolute_url_references,
Expand Down Expand Up @@ -618,7 +625,9 @@ pub async fn get_client_chunking_context(
builder = builder
.hot_module_replacement()
.source_map_source_type(SourceMapSourceType::AbsoluteFileUri)
.dynamic_chunk_content_loading(true);
.dynamic_chunk_content_loading(true)
// A manifest chunk keeps a lazily compiled import's URL stable across activation.
.manifest_chunks(*lazy_dynamic_imports.await?);
} else {
builder = builder
.chunking_config(
Expand Down
14 changes: 14 additions & 0 deletions crates/next-core/src/next_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1416,6 +1416,9 @@ pub struct ExperimentalConfig {
turbopack_worker_asset_prefix: Option<RcStr>,
turbopack_client_side_nested_async_chunking: Option<bool>,
turbopack_server_side_nested_async_chunking: Option<bool>,
/// Compile client dynamic import targets when their runtime proxy is first activated.
/// Development only.
turbopack_lazy_dynamic_imports: Option<bool>,
turbopack_import_type_bytes: Option<bool>,
/// Disable automatic configuration of the sass loader.
#[serde(default)]
Expand Down Expand Up @@ -2741,6 +2744,17 @@ impl NextConfig {
}))
}

#[turbo_tasks::function]
pub async fn turbopack_lazy_dynamic_imports(&self, next_mode: NextMode) -> Vc<bool> {
Vc::cell(
next_mode.is_development()
&& self
.experimental
.turbopack_lazy_dynamic_imports
.unwrap_or(false),
)
}

#[turbo_tasks::function]
pub async fn turbopack_import_type_bytes(&self) -> Vc<bool> {
Vc::cell(
Expand Down
6 changes: 6 additions & 0 deletions crates/next-core/src/next_shared/webpack_rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,11 @@ pub async fn webpack_loader_options(
rcstr!("web")
},
);
let mode = if builtin_conditions.contains(&WebpackLoaderBuiltinCondition::Development) {
rcstr!("development")
} else {
rcstr!("production")
};

Ok(Vc::cell(Some(
WebpackLoadersOptions {
Expand All @@ -166,6 +171,7 @@ pub async fn webpack_loader_options(
.to_resolved()
.await?,
target,
mode,
}
.resolved_cell(),
)))
Expand Down
19 changes: 18 additions & 1 deletion crates/next-napi-bindings/src/next_api/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use next_api::{
},
project::{
DebugBuildPaths, DefineEnv, DraftModeOptions, PartialProjectOptions, Project,
ProjectContainer, ProjectOptions, WatchOptions,
ProjectContainer, ProjectOptions, WatchOptions, activate_lazy_chunk_operation,
},
project_asset_hashes_manifest::immutable_hashes_manifest_asset_if_enabled,
route::{Endpoint, EndpointGroupKey, Route},
Expand Down Expand Up @@ -747,6 +747,23 @@ pub async fn project_update(
.await
}

#[tracing::instrument(level = "info", name = "activate lazy chunk", skip_all)]
#[napi]
pub async fn project_activate_lazy_chunk(
#[napi(ts_arg_type = "{ __napiType: \"Project\" }")] project: &External<ProjectInstance>,
chunk_path: RcStr,
) -> napi::Result<bool> {
let ctx = &project.turbopack_ctx;
ctx.turbo_tasks()
.run(async move {
Ok(*activate_lazy_chunk_operation(chunk_path)
.read_strongly_consistent()
.await?)
})
.await
.map_err(|error| napi::Error::from_reason(PrettyPrintError(&error.into()).to_string()))
}

/// Invalidates the filesystem cache so that it will be deleted next time that a turbopack project
/// is created with filesystem cache enabled.
#[napi]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,6 @@ Turbopack uses the [`loader-runner`](https://github.com/webpack/loader-runner) l
- [`fs`](https://webpack.js.org/api/loaders/#thisfs) - Partial support: only `fs.readFile` is currently implemented.
- [`emitFile`](https://webpack.js.org/api/loaders/#thisemitfile) - No support

**Context properties:**

- [`version`](https://webpack.js.org/api/loaders/#thisversion) - No support
- [`mode`](https://webpack.js.org/api/loaders/#thismode) - No support

**Utilities:**

- [`utils`](https://webpack.js.org/api/loaders/#thisutils) - No support
Expand Down
4 changes: 2 additions & 2 deletions examples/reproduction-template/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
},
"dependencies": {
"next": "canary",
"react": "19.2.8",
"react-dom": "19.2.8"
"react": "19.3.0",
"react-dom": "19.3.0"
},
"devDependencies": {
"@types/node": "^22",
Expand Down
30 changes: 15 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -255,24 +255,24 @@
"pretty-ms": "7.0.0",
"random-seed": "0.3.0",
"react": "19.0.0",
"react-builtin": "npm:react@19.3.0-canary-6c0e1047-20260908",
"react-builtin": "npm:react@19.3.0-canary-019019be-20260911",
"react-dom": "19.0.0",
"react-dom-builtin": "npm:react-dom@19.3.0-canary-6c0e1047-20260908",
"react-dom-experimental-builtin": "npm:react-dom@0.0.0-experimental-6c0e1047-20260908",
"react-experimental-builtin": "npm:react@0.0.0-experimental-6c0e1047-20260908",
"react-is-builtin": "npm:react-is@19.3.0-canary-6c0e1047-20260908",
"react-server-dom-turbopack": "npm:react-server-dom-turbopack@19.3.0-canary-6c0e1047-20260908",
"react-server-dom-turbopack-experimental": "npm:react-server-dom-turbopack@0.0.0-experimental-6c0e1047-20260908",
"react-server-dom-webpack": "npm:react-server-dom-webpack@19.3.0-canary-6c0e1047-20260908",
"react-server-dom-webpack-experimental": "npm:react-server-dom-webpack@0.0.0-experimental-6c0e1047-20260908",
"react-dom-builtin": "npm:react-dom@19.3.0-canary-019019be-20260911",
"react-dom-experimental-builtin": "npm:react-dom@0.0.0-experimental-019019be-20260911",
"react-experimental-builtin": "npm:react@0.0.0-experimental-019019be-20260911",
"react-is-builtin": "npm:react-is@19.3.0-canary-019019be-20260911",
"react-server-dom-turbopack": "npm:react-server-dom-turbopack@19.3.0-canary-019019be-20260911",
"react-server-dom-turbopack-experimental": "npm:react-server-dom-turbopack@0.0.0-experimental-019019be-20260911",
"react-server-dom-webpack": "npm:react-server-dom-webpack@19.3.0-canary-019019be-20260911",
"react-server-dom-webpack-experimental": "npm:react-server-dom-webpack@0.0.0-experimental-019019be-20260911",
"react-ssr-prepass": "1.0.8",
"react-virtualized": "9.22.3",
"request-promise-core": "1.1.2",
"resolve-from": "5.0.0",
"sass": "1.54.0",
"satori": "0.29.0",
"scheduler-builtin": "npm:scheduler@0.28.0-canary-6c0e1047-20260908",
"scheduler-experimental-builtin": "npm:scheduler@0.0.0-experimental-6c0e1047-20260908",
"scheduler-builtin": "npm:scheduler@0.28.0-canary-019019be-20260911",
"scheduler-experimental-builtin": "npm:scheduler@0.0.0-experimental-019019be-20260911",
"seedrandom": "3.0.5",
"semver": "7.3.7",
"serve-handler": "6.1.6",
Expand Down Expand Up @@ -316,10 +316,10 @@
"@types/react-dom": "19.2.4",
"@types/retry": "0.12.0",
"jest-snapshot": "30.0.0-alpha.6",
"react": "npm:react@19.3.0-canary-6c0e1047-20260908",
"react-dom": "npm:react-dom@19.3.0-canary-6c0e1047-20260908",
"react-is": "npm:react-is@19.3.0-canary-6c0e1047-20260908",
"scheduler": "npm:scheduler@0.28.0-canary-6c0e1047-20260908"
"react": "npm:react@19.3.0-canary-019019be-20260911",
"react-dom": "npm:react-dom@19.3.0-canary-019019be-20260911",
"react-is": "npm:react-is@19.3.0-canary-019019be-20260911",
"scheduler": "npm:scheduler@0.28.0-canary-019019be-20260911"
},
"packageExtensions": {
"eslint-plugin-react-hooks@0.0.0-experimental-6de32a5a-20250822": {
Expand Down
2 changes: 1 addition & 1 deletion packages/create-next-app/templates/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { Bundler, GetTemplateFileArgs, InstallTemplateArgs } from "./types";

// Do not rename or format. sync-react script relies on this line.
// prettier-ignore
const nextjsReactPeerVersion = "19.2.8";
const nextjsReactPeerVersion = "19.3.0";
function sorted(obj: Record<string, string>) {
return Object.keys(obj)
.sort()
Expand Down
5 changes: 5 additions & 0 deletions packages/next/src/build/swc/generated-native.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,11 @@ export declare function parse(
signal?: AbortSignal | undefined | null
): Promise<string>

export declare function projectActivateLazyChunk(
project: { __napiType: 'Project' },
chunkPath: RcStr
): Promise<boolean>

export declare function projectClientHmrChunkNamesSubscribe(
project: { __napiType: 'Project' },
func: (err: Error, value: TurbopackResult<HmrChunkNames>) => void
Expand Down
4 changes: 4 additions & 0 deletions packages/next/src/build/swc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,10 @@ function bindingToApi(
)
}

async activateLazyChunk(chunkPath: string): Promise<boolean> {
return binding.projectActivateLazyChunk(this._nativeProject, chunkPath)
}

async writeAnalyzeData(
appDirOnly: boolean
): Promise<TurbopackResult<void>> {
Expand Down
2 changes: 2 additions & 0 deletions packages/next/src/build/swc/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,8 @@ export interface UpdateInfo {
export interface Project {
update(options: Partial<ProjectOptions>): Promise<void>

activateLazyChunk(chunkPath: string): Promise<boolean>

writeAnalyzeData(appDirOnly: boolean): Promise<TurbopackResult<void>>

getAllCompilationIssues(): Promise<TurbopackResult<void>>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26981,7 +26981,7 @@
if (documentPosition & Node.DOCUMENT_POSITION_CONTAINS) {
if (null === otherFiber)
return (
(otherFiber = otherNode.ownerDocument),
(otherFiber = getOwnerDocumentFromRootContainer(otherNode)),
otherNode === otherFiber ||
otherNode === otherFiber.documentElement ||
otherNode === otherFiber.body
Expand Down Expand Up @@ -33463,11 +33463,11 @@
};
(function () {
var isomorphicReactPackageVersion = React.version;
if ("19.3.0-experimental-6c0e1047-20260908" !== isomorphicReactPackageVersion)
if ("19.3.0-experimental-019019be-20260911" !== isomorphicReactPackageVersion)
throw Error(
'Incompatible React versions: The "react" and "react-dom" packages must have the exact same version. Instead got:\n - react: ' +
(isomorphicReactPackageVersion +
"\n - react-dom: 19.3.0-experimental-6c0e1047-20260908\nLearn more: https://react.dev/warnings/version-mismatch")
"\n - react-dom: 19.3.0-experimental-019019be-20260911\nLearn more: https://react.dev/warnings/version-mismatch")
);
})();
("function" === typeof Map &&
Expand Down Expand Up @@ -33504,10 +33504,10 @@
!(function () {
var internals = {
bundleType: 1,
version: "19.3.0-experimental-6c0e1047-20260908",
version: "19.3.0-experimental-019019be-20260911",
rendererPackageName: "react-dom",
currentDispatcherRef: ReactSharedInternals,
reconcilerVersion: "19.3.0-experimental-6c0e1047-20260908"
reconcilerVersion: "19.3.0-experimental-019019be-20260911"
};
internals.overrideHookState = overrideHookState;
internals.overrideHookStateDeletePath = overrideHookStateDeletePath;
Expand Down Expand Up @@ -33655,7 +33655,7 @@
listenToAllSupportedEvents(container);
return new ReactDOMHydrationRoot(initialChildren);
};
exports.version = "19.3.0-experimental-6c0e1047-20260908";
exports.version = "19.3.0-experimental-019019be-20260911";
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
"function" ===
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18370,7 +18370,7 @@ function validateDocumentPositionWithFiberTree(
if (documentPosition & Node.DOCUMENT_POSITION_CONTAINS) {
if (null === otherFiber)
return (
(otherFiber = otherNode.ownerDocument),
(otherFiber = getOwnerDocumentFromRootContainer(otherNode)),
otherNode === otherFiber ||
otherNode === otherFiber.documentElement ||
otherNode === otherFiber.body
Expand Down Expand Up @@ -20458,14 +20458,14 @@ ReactDOMHydrationRoot.prototype.unstable_scheduleHydration = function (target) {
};
var isomorphicReactPackageVersion$jscomp$inline_2236 = React.version;
if (
"19.3.0-experimental-6c0e1047-20260908" !==
"19.3.0-experimental-019019be-20260911" !==
isomorphicReactPackageVersion$jscomp$inline_2236
)
throw Error(
formatProdErrorMessage(
527,
isomorphicReactPackageVersion$jscomp$inline_2236,
"19.3.0-experimental-6c0e1047-20260908"
"19.3.0-experimental-019019be-20260911"
)
);
ReactDOMSharedInternals.findDOMNode = function (componentOrElement) {
Expand All @@ -20487,10 +20487,10 @@ ReactDOMSharedInternals.findDOMNode = function (componentOrElement) {
};
var internals$jscomp$inline_2892 = {
bundleType: 0,
version: "19.3.0-experimental-6c0e1047-20260908",
version: "19.3.0-experimental-019019be-20260911",
rendererPackageName: "react-dom",
currentDispatcherRef: ReactSharedInternals,
reconcilerVersion: "19.3.0-experimental-6c0e1047-20260908"
reconcilerVersion: "19.3.0-experimental-019019be-20260911"
};
if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
var hook$jscomp$inline_2893 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
Expand Down Expand Up @@ -20597,4 +20597,4 @@ exports.hydrateRoot = function (container, initialChildren, options) {
listenToAllSupportedEvents(container);
return new ReactDOMHydrationRoot(initialChildren);
};
exports.version = "19.3.0-experimental-6c0e1047-20260908";
exports.version = "19.3.0-experimental-019019be-20260911";
Loading
Loading