* fix(app-router): isolate production page CSS chunks
Production App Router builds statically imported every page module into the generated RSC manifest. That let Vite/Rolldown concatenate page-level global CSS from sibling routes into shared CSS assets, so a sibling hash page with scroll-padding-top changed native hash scroll offsets on unrelated pages.
The manifest now emits cached dynamic loaders for page modules and loads the matched page module at the route dispatch boundary. Page generateStaticParams sources use the same loader with an explicit missing-export sentinel so prerender still distinguishes absent exports from malformed results.
* test(app-router): add focused unit test for route module loader
Address the non-blocking review note from PR #1738: per AGENTS.md, behavior
moved out of a template string should get a focused helper test. Cover
createRouteModuleLoader (promise dedup, rejection propagation),
loadRouteModules (page assignment, concurrent dedup, no-op cases, missing
`page` key) and loadRouteMatch (null short-circuit, match load).
Also cover createLazyGenerateStaticParamsSource (delegation, missing
sentinel for null/empty/non-function exports).
Document the rejected-load cache intent and the per-request intercept copy
in the WeakMap so future readers don't try to "fix" them as bugs.
* test: stabilize dev overlay HMR recovery
* chore: retrigger ci
* chore: fix knip check config
* test(app-router): guard intercepted modal CSS + load lazy page before probe
Adds the positive-direction guard the bonk review asked for: navigating
/feed -> intercepted /photos/[id] must load the lazy modal page and emit
its scroll-padding-top CSS chunk. The existing test only proved the
negative (CSS absent on a direct /feed visit), so a regression where the
lazy modal page failed to load its CSS would have passed silently.
Also fixes the probePage() intercept branch, which read intercept.page
without resolving the now-lazy __pageLoader. The render path awaits the
loader (resolveAppPageInterceptState), but the probe path did not, so the
dynamic-bailout probe silently inspected an undefined component and never
observed the intercept page's searchParams/headers access. Resolve the
lazy page before probing to match the render path.
---------
Co-authored-by: James <james@eli.cx>
* fix: support root-params dynamic getters during static prerendering and SSR
* fix: enforce strict parameter isolation for root params in prerendering and SSR
* fix: correct parameter mapping in multi-source resolver and clean up handleSsr fallback
* fix: use dedicated standalone ALS for root-params outside of unified request context
* fix: thread root params through generated app page dispatch
Normal App Router page requests computed root params in the typed handler, but the generated RSC entry did not forward them into page dispatch. SSR then received an empty root params scope for requests that should expose root params.
Destructure and forward rootParams in the generated entry, assert that template wiring, reuse the shared root-param picker, and align the scope helper API with the existing runWith overload pattern.
* fix(app-router): match Next.js RSC Content-Type (no charset suffix)
Next.js sets the RSC (React Server Components / 'flight') response
Content-Type to exactly 'text/x-component' (RSC_CONTENT_TYPE_HEADER in
.nextjs-ref/packages/next/src/client/components/app-router-headers.ts:17,
used by FlightRenderResult in
.nextjs-ref/packages/next/src/server/app-render/flight-render-result.ts:15).
vinext was sending 'text/x-component; charset=utf-8'. The suffix breaks
Next.js's own segment-cache deduplication checks (action-handler.ts uses
.startsWith(RSC_CONTENT_TYPE_HEADER) on the unsuffixed string) and fails
Next.js e2e tests that assert strict equality, e.g.:
- test/e2e/app-dir/app/index.test.ts L362, L371
- test/e2e/app-dir/segment-cache/deployment-skew/deployment-skew.test.ts L80
Replace the duplicated literal at seven sites with the existing
VINEXT_RSC_CONTENT_TYPE constant in app-rsc-cache-busting.ts.
* fix(app-router): match Next.js 404 plain-text body 'This page could not be found'
Next.js's plain-text 404 response body is exactly
'This page could not be found' (no trailing period in the response body;
the React-rendered not-found component uses the same text with a period).
vinext was returning 'Not Found' / '404 Not Found' / '404 - Not found',
which fails Next.js e2e tests that assert .toContain('This page could
not be found'), e.g.:
- test/e2e/app-dir/app/index.test.ts (several cases)
- test/e2e/app-dir/parallel-route-not-found/parallel-route-not-found.test.ts L52
- test/e2e/app-dir/prefetching-not-found/prefetching-not-found.test.ts L16
Next.js source citations (in .nextjs-ref):
- packages/next/src/server/route-modules/pages/pages-handler.ts L121, L535
- packages/next/src/build/templates/app-route.ts L170, L349
- packages/next/src/build/templates/app-page.ts L701, L1043
- packages/next/src/pages/_error.tsx L7
- packages/next/src/client/components/builtin/not-found.tsx L7 (HTML variant)
Updates the body in notFoundResponse() and the open-redirect / pages-router
SSR-fallback / worker-entry inline 404 sites. The HTTP status reason phrase
('Not Found') is unchanged. Route-specific bodies like '404 - API route not
found' are intentionally retained.