next.js
6dd4b27b - Turbopack: chain the Pages Router development client module graph (#98823)

Commit
7 days ago
Turbopack: chain the Pages Router development client module graph (#98823) ### What? Chains the Pages Router **development** client module graph so that `/_app` and the page being chunked live in the same `ModuleGraph`. This is PR 1 of a six-PR stack, based on `canary` (#98733, #99686 and #99749 are already merged): 1. **This PR** — Pages Router dev client graph chaining 2. #99910 — regression test for Pages Router `_app` availability (#99789) 3. #98734 — use graph-derived merged groups 4. #99750 — chunking takes a `ChunkGroupKey` 5. #98685 — chunk-group availability bitmaps 6. #99050 — keyed chunk-group index lookups ### Why? In development `Project::per_page_module_graph()` is true, so every page endpoint builds its own client `ModuleGraph`, each with its own `ChunkGroupInfo` and its own index space starting at `0`. `/_app` is always loaded before the page in the browser, so the page reuses `/_app`'s availability when chunking. Today that availability is a set of concrete modules, which is graph-independent, so the split graphs go unnoticed. That stops being true as soon as availability is expressed as chunk-group indices (#98685): `/_app` would record index `0` in *its* graph, and the page would resolve that same `0` against *its own* graph — where it means the page's own entry group. Every module of the group being chunked then looks already-available and is dropped, producing runtime errors like: ``` Module [hmr-entry]/hmr-entry.js { ENTRY => "[project]/pages/_error" } was instantiated as a runtime entry of chunk …, but the module factory is not available. ``` ### How? - `PageEndpoint::client_module_graph` builds a graph *chain* in per-page mode: `/_app`'s entry group first, then the page's, with `VisitedModules` threaded between them — the same layout-segment approach `ssr_module_graph` already uses for document → app → page. - Whole-app mode (production) is unchanged and still goes through `module_graph_for_modules`. - `/_app` itself is not chained onto anything. - Extracts a small `client_entry_modules` helper, since the entry module list is now needed in two places. Availability is still carried as the set of modules `/_app` emitted. Making the two endpoints share one graph also fixes #99789: with separate graphs, batching in the page graph could produce a node for a module shared with `/_app` whose edges point at page-only modules, and those modules were skipped as already available ("module factory is not available" on hydration). #99910 adds the regression test. Lining up the graph identities is also what #98685 builds on. ### Verification - `turbopack-core` — 160 passed - `next-core` — 84 passed - Turbopack snapshots — 125 passed - `404-page-router` and `server-navigation-error` development suites - Affected Cargo checks and Rust formatting <!-- NEXT_JS_LLM --> <!-- fleet 4f67c6f7-bbe2-454b-9a17-822a60ef8f7e --> Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com> Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com>
Author
Parents
Loading