fix(build): make vinext shim chunk rule reachable for installed copies - #2795
fix(build): make vinext shim chunk rule reachable for installed copies#2795Jbithell wants to merge 1 commit into
Conversation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UZCcfdorsm8PP13sL5tYK1
commit: |
There was a problem hiding this comment.
Pull request overview
This PR fixes client production chunk grouping so vinext’s own compiled shims still get grouped into the "vinext" chunk when vinext is installed from npm (i.e., shims live under <app>/node_modules/vinext/dist/shims/). This prevents Rolldown’s graph-based splitting from scattering shims into separate chunks that can form static import cycles with the browser entry chunk and break hydration at runtime.
Changes:
- Make the
"vinext"shims grouping check run before thenode_modulesearly-return logic increateClientManualChunks. - Reuse the hoisted
slashedIdfor thereact-domsubpath classification. - Add unit tests covering the “installed layout” (
.../node_modules/vinext/dist/shims/...) and ensuring existing route-boundary exclusions and framework grouping remain intact.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
packages/vinext/src/build/client-build-config.ts |
Moves shims detection ahead of the node_modules branch so installed-copy shims reliably map to the "vinext" chunk; reuses slashedId in the react-dom path logic. |
tests/build-optimization.test.ts |
Adds focused regression tests for installed-layout shim IDs, plus assertions that preserve-route-boundary and framework/vendor behavior is unchanged. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Performance benchmarksCompared 0 improved · 0 regressed · 6 within ±1.5%
View detailed results and traces 🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head |
Closes #2794
Problem
createClientManualChunksinsrc/build/client-build-config.tsreturns earlyfor every module id containing
node_modules. For an installed copy of vinext,its own client shims live at
<app>/node_modules/vinext/dist/shims/, so theyhit that early return —
getPackageName()yields"vinext", which matches noframework package — and the
shimsDirbranch below is never reached. The"vinext"chunk therefore never forms for any app installing vinext from npm;it only forms from a linked checkout.
Left to graph-based splitting, the shims scatter: in a real production build
(
1.0.0-beta.4, Workers target, App Router),shims/navigation-context-state.jslanded inside the browser entry chunk while
shims/slot.js,shims/error-boundary.js, andshims/navigation.jsbecame separateclient-reference chunks, each in a static import cycle with the entry:
Chunks are ES modules, so the chunk closing the cycle evaluates before the
entry's body has run.
slot.jscallsgetBfcacheIdMapContext()at modulescope; that helper reads
.createContextoff the entry chunk's hoistedvar F = __toESM(requireReact(), 1), which is stillundefined:This throws during entry evaluation, so hydration never happens — the site
server-renders and is completely inert. The build succeeds and dev is
unaffected (it doesn't chunk the same way), so nothing in the toolchain
catches it.
Fix
Check the shims prefix before the
node_modulesbranch.shimsDiris anabsolute path into vinext's own
dist/shims/, so the check is unambiguous inboth installed and linked layouts, and no react/react-dom/scheduler id can
start with it — the
frameworkandreact-dom-servergroupings areunaffected. The
react-dombranch now reuses the hoistedslashedIdinsteadof computing its own.
No change to
shimsDirconstruction is needed: it comes from pathslash, whoseresolvealready guarantees forward slashes on Windows.Verification
.../node_modules/vinext/dist/shims/slot.js)now maps to
"vinext"(fails onmain), route-owned shims are stillexcluded under
preserveRouteBoundaries, and framework/vendor/app ids areunchanged — verified against the shipped implementation across 17 id shapes,
including pnpm layouts and
?querysuffixes.vinext-*chunkforms, the three cycles disappear, and the entry evaluates cleanly.
Notes
RestorableClientStateController is not a constructor) — beta.0 & beta.1 #2620. fix(app-router): defer browser runtime controller creation #2621 made one controller lazilyconstructed but left the cyclic chunk graph in place (its own doc comment
says the modules "may land in a circular production chunk graph"); this PR
fixes the grouping so the cycles don't form at all.
route-boundary tuning in perf(client): preserve App Router route chunk boundaries #2189/perf(client): preserve additional route-owned shims #2205 has effectively been a no-op for npm
users; with this fix it takes effect as intended.
codeSplitting.groupsentry for the client environment withtest: /[\\/]node_modules[\\/]vinext[\\/]dist[\\/]shims[\\/]/— groupsconcatenate, so vinext's own
frameworkgroup is unaffected.