Skip to content

perf(turbopack): add opt-in dynamic HMR chunk lists#169

Open
fireairforce wants to merge 1 commit into
utoofrom
zoomdong/split-hmr-chunk-lists
Open

perf(turbopack): add opt-in dynamic HMR chunk lists#169
fireairforce wants to merge 1 commit into
utoofrom
zoomdong/split-hmr-chunk-lists

Conversation

@fireairforce

@fireairforce fireairforce commented Jul 20, 2026

Copy link
Copy Markdown
Member

Summary

Large applications currently place every transitively reachable dynamic chunk in the entry HMR chunk list. A small edit can therefore invalidate and recompute a much larger graph than the active page needs.

This PR adds an opt-in dynamic HMR list mode:

  • keep only direct chunks and caller-provided extras in the entry HMR list;
  • emit one lightweight manifest bootstrap for each async chunk group;
  • include manifest and member content versions;
  • validate the subscription baseline before loading versioned members;
  • revalidate after the HTTP loads before exposing the dynamic import;
  • keep ordinary updates to one active, unshared dynamic list on the HMR path.

In the Ant Design + dumi reproduction, this reduces the entry HMR list from about 4,628 chunk references to 2.

The fork surface is intentionally limited to Turbopack browser chunking and runtime code: 7 files, with no Next.js dev-server, CLI, or application-client integration changes.

Opt-in and compatibility

The feature is disabled by default. Existing Next.js/Turbopack output and HMR behavior are unchanged unless a caller explicitly enables:

BrowserChunkingContextBuilder::dynamic_hmr_chunk_lists()

Utoo enables it together with HMR. This PR alone does not enable the optimization for stock Next.js applications.

Transport contract

The opt-in mode depends on the Utoo HMR server providing three guarantees:

  1. pass the subscription's expected version to the underlying HMR event stream;
  2. echo the subscription's validation token on baseline and update messages;
  3. batch all chunk-list updates produced by one project build into one browser transaction.

The validation token prevents frames from an obsolete subscription generation from mutating current state. Batching lets the runtime detect a multi-list update and reload before partially applying an ambiguous transaction. A server that does not implement this contract must leave the feature disabled.

Conservative fallback policy

The fast path is intentionally narrow. A single active dynamic list with no shared members can update without reloading.

The runtime reloads conservatively for ambiguous or stale state, including:

  • multiple dynamic lists changing in one build;
  • a member shared by more than one active dynamic list;
  • dynamic chunk-list structure changes;
  • a list changing while its members are loading;
  • baseline or expected-version mismatches;
  • missing member versions, failed versioned loads, or failed validation;
  • a dynamic list disappearing or returning notFound.

This keeps the reduced dependency graph without adding a large cross-list transaction engine to the fork. After a successful dynamic HMR update, a later socket reconnect validates against the original manifest version and safely reloads.

Worker scope

The subscribe/load/revalidate handshake is browser-only. When document is unavailable, such as in a Worker, the runtime loads manifest members directly and completes the dynamic import without waiting for the browser HMR transport. A load failure restarts the runtime. This PR does not claim dynamic-list HMR optimization for Workers.

Validation

Check Result Coverage
npm run build:local --workspace @utoo/pack Passed Full local Rust/N-API/JS integration build
npm run test:e2e:pack-hmr 9/9 First-load race, post-load revalidation, reconnect, single-list HMR, shared JS/CSS reloads, removal/restore, disappearing bootstrap
cargo test -p pack-tests --test snapshot dynamic_chunk_lists -- --ignored 2/2 Dynamic-list split and metadata; hot: false direct loading
Targeted @utoo/pack HMR and WebSocket Vitest suites 27/27 Server validation echo, subscription lifecycle, routing, reconnect, and build batching
cargo clippy -p turbopack-browser --all-targets with warnings denied Passed Modified Rust integration
Rustfmt, Prettier, ESLint, and git diff --check Passed Formatting and static checks

The standalone runtime TypeScript check reports the same existing diagnostics on origin/utoo; this diff introduces no additional diagnostics.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the enable_dynamic_hmr_chunk_lists option to BrowserChunkingContext, allowing separate HMR chunk lists to be generated for each dynamic chunk group instead of recursively adding all reachable dynamic chunks to the entry chunk list. Feedback on the changes highlights a potential issue where a redundant dynamic HMR chunk list register chunk is generated for the entry chunk group, which already has its own registration. It is recommended to skip this generation when the current chunk group is the root entry chunk group.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread turbopack/crates/turbopack-browser/src/chunking_context.rs Outdated
@fireairforce
fireairforce force-pushed the zoomdong/split-hmr-chunk-lists branch from e9fc719 to 8c80c8b Compare July 21, 2026 12:04
@fireairforce

Copy link
Copy Markdown
Member Author

安全加固已补齐并推送:动态 chunk list 现在先建立带 expectedVersion/validation token 的 HMR baseline,成员 HTTP 加载后再二次校验;更新按 batch 去重,JS/CSS 使用内容版本 URL 并做精确 owner/清理;missing、重连、旧帧和并发 generation 均有终止路径。standalone WebSocket 也补了 clean close 重连。验证:相关 cargo check/clippy 通过;Utoo 侧真实 Chromium HMR E2E 8 个场景 repeat 3,共 24/24 通过。

@fireairforce
fireairforce force-pushed the zoomdong/split-hmr-chunk-lists branch from facf050 to 3d57cc1 Compare July 23, 2026 03:15
@fireairforce fireairforce changed the title perf(turbopack): split dynamic HMR chunk lists perf(turbopack): add opt-in dynamic HMR chunk lists Jul 23, 2026
@fireairforce
fireairforce force-pushed the zoomdong/split-hmr-chunk-lists branch from 3d57cc1 to 93353e1 Compare July 23, 2026 03:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant