Commit Graph

1420 Commits

Author SHA1 Message Date
James Anderson 5e19a2dd38 fix(config): honor resolve extensions and improve webpack config processing (#1959)
* fix(config): honor resolve extensions

* fix(config): preserve resolve extension semantics

* fix(config): preserve resolve extensions fallback

* fix(config): preserve resolver environment semantics

* fix(config): treat Vite preview as production
2026-06-12 22:55:06 +00:00
James Anderson 3ba2528c14 fix(app-router): preserve page notFound precedence during metadata failure (#1957) 2026-06-12 23:18:27 +01:00
James Anderson 075919357e fix(router): hard navigate Pages links to App routes (#1960)
* fix(router): hard navigate pages links to app routes

* fix(router): normalize localized app route detection
2026-06-12 22:45:19 +01:00
James Anderson 222f18b0d9 fix(css): load local CommonJS PostCSS plugins (#1961)
* fix(css): load local CommonJS PostCSS plugins

* fix(css): avoid temporary PostCSS plugin copies
2026-06-12 22:42:33 +01:00
James Anderson 9e3cf90583 test(e2e): disable hash fixture query prefetch (#1948) 2026-06-12 13:04:10 +00:00
Nathan Nguyen da26f42d7a refactor(router): classify server-action results and RSC navigation errors in planner (#1901)
* feat(router): classify server-action results and RSC navigation errors in planner

The navigation executor in app-browser-entry.ts performed ad-hoc compatibility
checks for server action responses using two separate helpers:
resolveServerActionRedirectCompatibilityHardNavigationTarget and
resolveRscCompatibilityNavigationDecision. These checks were scattered in
the executor and mixed decision logic with side effects (clearClientNavigationCaches,
performHardNavigation).

This change introduces two pure classifiers in the navigation planner:

- classifyServerActionResult: decides whether a server action response should
  hard-navigate (due to build skew) or proceed. For redirect responses, it
  returns the redirect href with appropriate history mode (assign for push,
  replace for replace). For non-redirect RSC responses, it reloads currentHref.
  A null clientCompatibilityId is treated as always compatible.

- classifyRscNavigationError: always hard-navigates to currentHref on any
  RSC navigation error, providing a NavigationTrace for observability.

Both classifiers produce typed DecisionV0 shapes with NavigationTrace entries,
making the planner the single semantic authority for all navigation outcomes.

The executor is updated to call these classifiers instead of the ad-hoc
helpers, and the now-unused imports are removed.

Test coverage: 9 new tests for classifyServerActionResult covering all 7
branches, and 1 test for classifyRscNavigationError.

* refactor(router): address review concerns on classifyServerActionResult planner

Three non-blocking concerns raised in code review:

1. compatibilityDecision.hardNavigationTarget was silently discarded in
   classifyServerActionResult without explanation. The helper computes a URL
   from responseUrl (the RSC action endpoint), which is wrong for user-visible
   navigation — the authoritative targets are actionRedirectHref and currentHref.
   Add a comment explaining the intentional discard.

2. The server action callback in app-browser-entry.ts computed the response
   content-type twice via separate raw string operations. Hoist the check
   into fetchResponseIsRsc so both consumers (classifyServerActionResult input
   and the non-RSC redirect guard) share one derived value.

3. The planner's decision dispatch was inlined in the executor, making it
   untestable without browser globals. Extract applyServerActionResultDecision
   into app-browser-action-result.ts and add an executor-level regression test
   that drives it with vi.fn() mocks — covering redirect push/replace, no-redirect
   reload, and proceed paths against the live classifyServerActionResult output.

* refactor(router): move applyServerActionResultDecision to dedicated navigation module

* refactor(router): remove old server-action redirect compatibility helper

Remove resolveServerActionRedirectCompatibilityHardNavigationTarget from
app-browser-action-result.ts and its tests. The planner's
classifyServerActionResult is now the single semantic authority for
server-action navigation decisions.

Add a wiring regression test that exercises the real browser-entry seam:
a synthetic Response has its facts extracted (content-type, redirect
headers, compatibility ID, response URL) and passed to the planner,
pinning the extraction boundary that app-browser-entry.ts performs at
runtime.

* refactor(router): extract server-action fact collector and remove stale helper

Extract  as the single pure boundary between
raw browser response data and the narrow facts expected by the navigation
planner. This removes the duplication where the wiring test had to hand-copy
the same extraction logic.

- Add  to .
- Use it in  so the inline normalisation disappears.
- Delete ; its logic is
  now folded into the helper's  field.
- Update tests to target the helper directly and assert the end-to-end
  wiring through the planner.

* fix(router): address server action planner review

---------

Co-authored-by: James <james@eli.cx>
2026-06-12 13:13:46 +01:00
Nathan Nguyen ba6ea6f6f8 fix(shims): add useUntrackedPathname hook for error boundary parity (#1933)
* feat(shims): add useUntrackedPathname hook for error boundary parity

Next.js upstream provides a useUntrackedPathname() hook
(packages/next/src/client/components/navigation-untracked.ts) that is
used by the unstable_catchError error boundary. Unlike usePathname(),
useUntrackedPathname():

- Returns null during the missing-params shell prerender (instead of "/")
- Does not register the pathname as a tracked render dependency, avoiding
  unnecessary re-renders of the error boundary

This commit:
1. Adds useUntrackedPathname() to packages/vinext/src/shims/navigation.ts
2. Switches packages/vinext/src/shims/error.tsx to use it
3. Adds unit tests covering server, client snapshot, and Pages Router paths

Refs:
- Next.js source: https://github.com/vercel/next.js/blob/v16.2.6/packages/next/src/client/components/navigation-untracked.ts
- Issue: https://github.com/cloudflare/vinext/issues/1920

* refactor(shims): move useUntrackedPathname to internal module

Address code review feedback on PR 1933:

- Move useUntrackedPathname from public next/navigation API to
  internal/navigation-untracked.ts to prevent public surface leak.

- Change server no-context fallback from null to '/' to match
  usePathname() semantics. Document that null is reserved for
  future missing-params shell detection.

- Update error.tsx to import from the internal module.

- Update shims tests to import from internal module and expect
  '/' for no-context SSR.

- Add integration test for unstable_catchError boundary contract:
  getDerivedStateFromProps clears errors on pathname changes and
  retains them when pathname stays the same.

* fix(shims): gate untracked pathname render snapshot with active count

Address second round of code review feedback on PR 1933:

- Gate client render snapshot with navigationSnapshotActiveCount > 0
  so the hook returns the pending URL only during active transitions.
  After commit, falls back to cached pathname so user pushState/
  replaceState calls are immediately reflected.

- Import getNavigationContext() from navigation.ts instead of
  duplicating the global accessor / hydration context logic.

- Add inverse test: provider snapshot present but inactive
  (navigationSnapshotActiveCount === 0) returns committed pathname,
  not stale provider value.

* test(shims): type-safe unstable_catchError boundary contract test

Export _CatchError, _CatchErrorInternalState, _CatchErrorProps,
_CatchErrorState, and _UserProps from error.tsx with @internal
annotations so tests can reference them without as-unknown-as
assertions.

Rewrite the getDerivedStateFromProps integration test to use
imported types instead of inline type assertions.

* chore: format with vp fmt

* fix(shims): keep _CatchError and underscore types local in error.tsx

Address review feedback: exporting _CatchError and underscore types from
next/error widened the public shim surface. Revert them to local types
and use structural typing in tests instead.

- Make _CatchError, _UserProps, _CatchErrorState, _CatchErrorProps, and
  _CatchErrorInternalState local again (non-exported).
- Update the getDerivedStateFromProps integration test to use structural
  as-unknown-as assertions instead of importing internal types.

* refactor(shims): extract shared Pages Router accessor to internal helper

Create packages/vinext/src/shims/internal/pages-router-accessor.ts
with getPagesNavigationContext() and PagesNavigationContext type.

Import from it in both navigation.ts and navigation-untracked.ts
instead of duplicating the Symbol lookup and error handling. This
prevents the string key and the accessor shape from drifting across
modules if a third consumer is added later.

router.ts still writes the global accessor directly using Symbol.for
as before.

* fix(shims): move pages-router-accessor import to top of navigation.ts

Move the import from the middle of the file to the top import block
and remove the unused PagesNavigationContext type import. Fixes
eslint no-unused-vars and import/first errors.

* ci: trigger rebuild

* refactor(shims): reuse navigation render snapshot hook

---------

Co-authored-by: James <james@eli.cx>
2026-06-12 12:06:47 +01:00
Divanshu Chauhan cd921ab709 perf: cache fs probes and precompute route sort keys in scan/deploy paths (#1930)
* perf(routing): precompute route precedence before sorting

`compareRoutes` re-parsed every pattern on each comparison, so a sort
called `routePrecedence` ~2·log n times per route instead of once. Replace
it with `sortRoutes`, which scores each pattern once into a Map and sorts
by (score, pattern.localeCompare). The localeCompare tiebreaker already
guarantees a total order, so ordering is byte-identical; this just removes
the redundant re-parsing on every route scan (dev re-scans on file change,
plus the pages/api and app-graph builds).

* perf(app-router): cache convention-file probes per route-graph scan

`buildAppRouteGraph` walks the appDir→leaf chain separately for every
route (layouts, templates, errors, boundaries, slots), each step probing
up to 4 extensions per convention file via `existsSync`. Shared ancestor
directories — the `app/` root above all — were re-stat'd once per
descendant route, so a scan cost roughly routes × depth × conventions ×
extensions syscalls.

Memoize `findFile` through a `WeakMap<ValidFileMatcher, Map>` keyed by a
per-scan matcher clone created in `buildAppRouteGraph`. Results are
immutable within one scan, so no invalidation is needed: the cache lives
exactly as long as the scan and is GC'd afterward. The fresh per-scan key
also keeps overlapping scans isolated, and the `null` not-found outcome is
cached too. Probe results are identical to the previous direct `existsSync`
calls.

* perf(deploy): single tree walk for detection and reuse parsed package.json

`analyzeProject` walked the app/ tree twice — once in `detectISR` and again
in `detectMDX` — and `detectNativeModules` re-read and re-parsed
package.json that `detectProject` had already parsed into `allDeps`.

Merge the two walkers into one `scanTreeForDetection(dir, { isr, mdx })`
that evaluates both predicates per entry with each flag short-circuiting
independently, extract the next.config MDX check into `detectMDXFromConfig`,
and add `resolveProjectDir` for the shared root/`src` precedence. Pass the
already-merged `allDeps` into `detectNativeModules`. Detection semantics are
unchanged: same files visited, same patterns tested, same booleans out.
2026-06-12 11:51:43 +01:00
Nathan Nguyen 79d78b0cce chore: standardize prod-build project commands in playwright.config.ts (#1932)
Replace error TS5058: The specified path does not exist: '../../../packages/vinext/tsconfig.json'. with
~/packages/vinext$ vp pack ⊘ cache disabled
ℹ entry: src/cache.ts, src/check.ts, src/cli-args.ts, src/cli.ts, src/deploy.ts, src/index.ts, src/init.ts, src/typegen.ts, src/build/assets-ignore.ts, src/build/clean-output.ts, src/build/client-build-config.ts, src/build/css-url-assets.ts, src/build/inline-css.ts, src/build/layout-classification-types.ts, src/build/layout-classification.ts, src/build/next-client-runtime-manifests.ts, src/build/nitro-route-rules.ts, src/build/precompress.ts, src/build/prerender.ts, src/build/report.ts, src/build/route-classification-injector.ts, src/build/route-classification-manifest.ts, src/build/run-prerender.ts, src/build/server-manifest.ts, src/build/ssr-manifest.ts, src/build/standalone.ts, src/build/static-export.ts, src/cache/cache-adapters-virtual.ts, src/client/empty-module.ts, src/client/instrumentation-client-inject.ts, src/client/instrumentation-client-state.ts, src/client/instrumentation-client.ts, src/client/navigation-runtime.ts, src/client/pages-router-link-navigation.ts, src/client/validate-module-path.ts, src/client/vinext-next-data.ts, src/client/window-next.ts, src/cloudflare/index.ts, src/cloudflare/tpr.ts, src/config/config-matchers.ts, src/config/dotenv.ts, src/config/next-config.ts, src/config/tsconfig-paths.ts, src/routing/app-route-graph.ts, src/routing/app-router.ts, src/routing/file-matcher.ts, src/routing/pages-router.ts, src/routing/route-matching.ts, src/routing/route-pattern.ts, src/routing/route-trie.ts, src/routing/route-validation.ts, src/routing/utils.ts, src/entries/app-browser-entry.ts, src/entries/app-rsc-entry.ts, src/entries/app-rsc-manifest.ts, src/entries/app-ssr-entry.ts, src/entries/pages-client-entry.ts, src/entries/pages-entry-helpers.ts, src/entries/pages-server-entry.ts, src/entries/runtime-entry-module.ts, src/plugins/ast-utils.ts, src/plugins/async-hooks-stub.ts, src/plugins/client-reference-dedup.ts, src/plugins/css-data-url.ts, src/plugins/dynamic-preload-metadata.ts, src/plugins/fonts.ts, src/plugins/import-meta-url.ts, src/plugins/instrumentation-client.ts, src/plugins/middleware-server-only.ts, src/plugins/og-assets.ts, src/plugins/optimize-imports.ts, src/plugins/postcss.ts, src/plugins/remove-console.ts, src/plugins/require-context.ts, src/plugins/rsc-client-reference-loaders.ts, src/plugins/rsc-client-shim-excludes.ts, src/plugins/sass.ts, src/plugins/server-externals-manifest.ts, src/plugins/strip-server-exports.ts, src/plugins/wasm-module-import.ts, src/shims/amp.ts, src/shims/app-router-scroll-state.ts, src/shims/app-router-scroll.tsx, src/shims/app.tsx, src/shims/before-interactive-context.tsx, src/shims/cache-for-request.ts, src/shims/cache-runtime.ts, src/shims/cache.ts, src/shims/cdn-cache.ts, src/shims/client-hook-error.ts, src/shims/client-locale.ts, src/shims/client-only.ts, src/shims/compat-router.ts, src/shims/config.ts, src/shims/constants.ts, src/shims/default-global-error.tsx, src/shims/default-not-found.tsx, src/shims/document.tsx, src/shims/dynamic-preload-chunks.tsx, src/shims/dynamic.ts, src/shims/error-boundary.tsx, src/shims/error.tsx, src/shims/fetch-cache.ts, src/shims/font-google-base.ts, src/shims/font-google.ts, src/shims/font-local.ts, src/shims/font-utils.ts, src/shims/form.tsx, src/shims/hash-scroll.ts, src/shims/head-state.ts, src/shims/head.ts, src/shims/headers.ts, src/shims/i18n-context.ts, src/shims/i18n-state.ts, src/shims/image-config.ts, src/shims/image.tsx, src/shims/layout-segment-context.tsx, src/shims/legacy-image.tsx, src/shims/link-prefetch.ts, src/shims/link.tsx, src/shims/metadata.tsx, src/shims/navigation-state.ts, src/shims/navigation.react-server.ts, src/shims/navigation.ts, src/shims/offline.ts, src/shims/og.tsx, src/shims/pages-router-runtime.ts, src/shims/ppr-fallback-shell.ts, src/shims/readonly-url-search-params.ts, src/shims/request-context.ts, src/shims/request-state-types.ts, src/shims/root-params.ts, src/shims/router-state.ts, src/shims/router.ts, src/shims/script-nonce-context.tsx, src/shims/script.tsx, src/shims/server-only.ts, src/shims/server.ts, src/shims/slot.tsx, src/shims/thenable-params.ts, src/shims/unified-request-context.ts, src/shims/unrecognized-action-error.ts, src/shims/url-safety.ts, src/shims/url-utils.ts, src/shims/use-merged-ref.ts, src/shims/web-vitals.ts, src/server/api-handler.ts, src/server/app-bfcache-id.ts, src/server/app-browser-action-result.ts, src/server/app-browser-client-reuse-manifest.ts, src/server/app-browser-entry.ts, src/server/app-browser-error.ts, src/server/app-browser-history-controller.ts, src/server/app-browser-hydration.ts, src/server/app-browser-interception-context.ts, src/server/app-browser-mpa-navigation.ts, src/server/app-browser-navigation-controller.ts, src/server/app-browser-popstate.ts, src/server/app-browser-rsc-redirect.ts, src/server/app-browser-state.ts, src/server/app-browser-stream.ts, src/server/app-browser-visible-commit.ts, src/server/app-client-reference-preloader.ts, src/server/app-elements-wire.ts, src/server/app-elements.ts, src/server/app-fallback-renderer.ts, src/server/app-history-state.ts, src/server/app-hook-warning-suppression.ts, src/server/app-inline-css-client.ts, src/server/app-interception-context-header.ts, src/server/app-layout-param-observation.ts, src/server/app-middleware.ts, src/server/app-mounted-slots-header.ts, src/server/app-optimistic-routing.ts, src/server/app-page-boundary-render.ts, src/server/app-page-boundary.ts, src/server/app-page-cache.ts, src/server/app-page-dispatch.ts, src/server/app-page-element-builder.ts, src/server/app-page-execution.ts, src/server/app-page-head.ts, src/server/app-page-method.ts, src/server/app-page-params.ts, src/server/app-page-probe.ts, src/server/app-page-render-identity.ts, src/server/app-page-render-observation.ts, src/server/app-page-render.ts, src/server/app-page-request.ts, src/server/app-page-response.ts, src/server/app-page-route-wiring.tsx, src/server/app-page-search-params-observation.ts, src/server/app-page-segment-state.ts, src/server/app-page-stream.ts, src/server/app-pages-bridge.ts, src/server/app-post-middleware-context.ts, src/server/app-ppr-fallback-shell.ts, src/server/app-prerender-endpoints.ts, src/server/app-prerender-static-params.ts, src/server/app-render-dependency.tsx, src/server/app-request-context.ts, src/server/app-route-handler-cache.ts, src/server/app-route-handler-dispatch.ts, src/server/app-route-handler-execution.ts, src/server/app-route-handler-policy.ts, src/server/app-route-handler-response.ts, src/server/app-route-handler-runtime.ts, src/server/app-route-module-loader.ts, src/server/app-router-entry.ts, src/server/app-rsc-cache-busting.ts, src/server/app-rsc-embedded-chunks.ts, src/server/app-rsc-error-handler.ts, src/server/app-rsc-errors.ts, src/server/app-rsc-handler.ts, src/server/app-rsc-render-mode.ts, src/server/app-rsc-request-normalization.ts, src/server/app-rsc-response-finalizer.ts, src/server/app-rsc-route-matching.ts, src/server/app-segment-config.ts, src/server/app-server-action-execution.ts, src/server/app-ssr-entry.ts, src/server/app-ssr-error-meta.ts, src/server/app-ssr-stream.ts, src/server/app-static-generation.ts, src/server/app-visited-response-cache.ts, src/server/artifact-compatibility.ts, src/server/cache-control.ts, src/server/cache-headers.ts, src/server/cache-proof.ts, src/server/client-reuse-manifest.ts, src/server/client-trace-metadata.ts, src/server/cookie-utils.ts, src/server/csp.ts, src/server/default-global-error-module.ts, src/server/default-not-found-module.ts, src/server/dev-error-overlay-store.ts, src/server/dev-error-overlay.tsx, src/server/dev-initial-server-error.ts, src/server/dev-lockfile.ts, src/server/dev-module-runner.ts, src/server/dev-origin-check.ts, src/server/dev-route-files.ts, src/server/dev-server.ts, src/server/dev-stack-sourcemap-endpoint.ts, src/server/dev-stack-sourcemap.ts, src/server/document-initial-head.ts, src/server/edge-api-runtime.ts, src/server/file-based-metadata.ts, src/server/headers.ts, src/server/html.ts, src/server/http-error-responses.ts, src/server/image-optimization.ts, src/server/implicit-tags.ts, src/server/instrumentation-runtime.ts, src/server/instrumentation.ts, src/server/isr-cache.ts, src/server/isr-decision.ts, src/server/metadata-route-build-data.ts, src/server/metadata-route-response.ts, src/server/metadata-routes.ts, src/server/middleware-matcher.ts, src/server/middleware-request-headers.ts, src/server/middleware-response-headers.ts, src/server/middleware-runtime.ts, src/server/middleware.ts, src/server/navigation-planner.ts, src/server/navigation-trace.ts, src/server/next-error-digest.ts, src/server/normalize-path.ts, src/server/otel-tracer-extension.ts, src/server/pages-api-route.ts, src/server/pages-asset-tags.ts, src/server/pages-body-parser-config.ts, src/server/pages-data-route.ts, src/server/pages-default-404.ts, src/server/pages-document-initial-props.ts, src/server/pages-get-initial-props.ts, src/server/pages-i18n.ts, src/server/pages-media-type.ts, src/server/pages-node-compat.ts, src/server/pages-page-data.ts, src/server/pages-page-handler.ts, src/server/pages-page-method.ts, src/server/pages-page-response.ts, src/server/pages-readiness.ts, src/server/pages-request-pipeline.ts, src/server/pages-revalidate.ts, src/server/pages-serializable-props.ts, src/server/pregenerated-concrete-paths.ts, src/server/prerender-route-params.ts, src/server/prerender-work-unit-setup.ts, src/server/prod-server.ts, src/server/proxy-trust.ts, src/server/request-log.ts, src/server/request-pipeline.ts, src/server/rsc-stream-hints.ts, src/server/seed-cache.ts, src/server/server-action-not-found.ts, src/server/server-globals.ts, src/server/skip-cache-proof.ts, src/server/socket-error-backstop.ts, src/server/static-file-cache.ts, src/server/static-layout-client-reuse-proof.ts, src/server/streaming-metadata.ts, src/server/worker-utils.ts, src/utils/asset-prefix.ts, src/utils/base-path.ts, src/utils/cache-control-metadata.ts, src/utils/client-build-manifest.ts, src/utils/client-entry-manifest.ts, src/utils/client-runtime-metadata.ts, src/utils/compare.ts, src/utils/dev-error-recovery-event.ts, src/utils/domain-locale.ts, src/utils/encode-cache-tag.ts, src/utils/error-cause.ts, src/utils/hash.ts, src/utils/html-limited-bots.ts, src/utils/lazy-chunks.ts, src/utils/manifest-paths.ts, src/utils/mdx-scan.ts, src/utils/navigation-signal.ts, src/utils/number.ts, src/utils/path.ts, src/utils/prerender-output-paths.ts, src/utils/project.ts, src/utils/promise.ts, src/utils/public-routes.ts, src/utils/query.ts, src/utils/record.ts, src/utils/regex.ts, src/utils/safe-json-file.ts, src/utils/sorted-array.ts, src/utils/text-stream.ts, src/utils/vinext-root.ts, src/utils/vite-version.ts, src/build/google-fonts/build-url.ts, src/build/google-fonts/fallback-metrics.ts, src/build/google-fonts/font-metadata.ts, src/build/google-fonts/get-axes.ts, src/build/google-fonts/sort-variants.ts, src/build/google-fonts/validate.ts, src/shims/internal/als-registry.ts, src/shims/internal/api-utils.ts, src/shims/internal/app-route-detection.ts, src/shims/internal/app-router-context.ts, src/shims/internal/cookie-serialize.ts, src/shims/internal/cookies.ts, src/shims/internal/link-status-registry.ts, src/shims/internal/make-hanging-promise.ts, src/shims/internal/pages-data-fetch-dedup.ts, src/shims/internal/pages-data-target.ts, src/shims/internal/pages-data-url.ts, src/shims/internal/parse-cookie-header.ts, src/shims/internal/route-pattern-for-warning.ts, src/shims/internal/router-context.ts, src/shims/internal/utils.ts, src/shims/internal/work-unit-async-storage.ts
ℹ target: node22.0.0
ℹ tsconfig: tsconfig.json
ℹ Build start
ℹ Cleaning 736 files
ℹ Granting execute permission to dist/cli.js
ℹ dist/index.js                                           104.22 kB │ gzip: 26.12 kB
ℹ dist/shims/navigation.js                                 67.62 kB │ gzip: 16.87 kB
ℹ dist/routing/app-route-graph.js                          59.75 kB │ gzip: 14.51 kB
ℹ dist/shims/router.js                                     55.70 kB │ gzip: 14.83 kB
ℹ dist/server/app-browser-entry.js                         53.69 kB │ gzip: 11.83 kB
ℹ dist/server/dev-error-overlay.js                         45.33 kB │ gzip: 10.72 kB
ℹ dist/server/prod-server.js                               44.54 kB │ gzip: 12.46 kB
ℹ dist/config/next-config.js                               41.77 kB │ gzip: 13.01 kB
ℹ dist/server/dev-server.js                                40.31 kB │ gzip:  9.69 kB
ℹ dist/config/config-matchers.js                           38.47 kB │ gzip: 12.36 kB
ℹ dist/deploy.js                                           38.45 kB │ gzip: 11.53 kB
ℹ dist/entries/app-rsc-entry.js                            36.62 kB │ gzip:  9.31 kB
ℹ dist/build/prerender.js                                  36.17 kB │ gzip:  9.45 kB
ℹ dist/check.js                                            35.06 kB │ gzip: 10.01 kB
ℹ dist/server/app-server-action-execution.js               32.42 kB │ gzip:  7.65 kB
ℹ dist/shims/metadata.js                                   31.86 kB │ gzip:  7.14 kB
ℹ dist/shims/cache.js                                      30.74 kB │ gzip:  9.04 kB
ℹ dist/plugins/fonts.js                                    30.73 kB │ gzip:  9.33 kB
ℹ dist/shims/fetch-cache.js                                28.38 kB │ gzip:  7.76 kB
ℹ dist/server/navigation-planner.js                        28.04 kB │ gzip:  5.52 kB
ℹ dist/server/cache-proof.js                               27.73 kB │ gzip:  5.76 kB
ℹ dist/shims/headers.js                                    27.63 kB │ gzip:  7.75 kB
ℹ dist/server/app-page-dispatch.js                         27.24 kB │ gzip:  6.20 kB
ℹ dist/cli.js                                              26.01 kB │ gzip:  7.96 kB
ℹ dist/shims/link.js                                       25.90 kB │ gzip:  7.08 kB
ℹ dist/server/app-page-route-wiring.js                     24.02 kB │ gzip:  4.81 kB
ℹ dist/server/app-page-render.js                           23.08 kB │ gzip:  5.49 kB
ℹ dist/shims/server.js                                     22.28 kB │ gzip:  6.87 kB
ℹ dist/build/report.js                                     20.84 kB │ gzip:  5.66 kB
ℹ dist/cloudflare/tpr.js                                   20.37 kB │ gzip:  6.76 kB
ℹ dist/shims/cache-runtime.js                              20.19 kB │ gzip:  6.45 kB
ℹ dist/server/request-pipeline.js                          19.80 kB │ gzip:  6.40 kB
ℹ dist/plugins/optimize-imports.js                         19.75 kB │ gzip:  5.46 kB
ℹ dist/server/app-elements-wire.js                         19.54 kB │ gzip:  4.57 kB
ℹ dist/server/app-browser-state.js                         19.06 kB │ gzip:  4.59 kB
ℹ dist/entries/pages-server-entry.js                       18.37 kB │ gzip:  5.09 kB
ℹ dist/shims/image.js                                      17.87 kB │ gzip:  5.31 kB
ℹ dist/server/file-based-metadata.js                       17.80 kB │ gzip:  4.08 kB
ℹ dist/server/app-browser-navigation-controller.js         17.72 kB │ gzip:  4.10 kB
ℹ dist/server/app-rsc-handler.js                           17.28 kB │ gzip:  4.29 kB
ℹ dist/server/dev-stack-sourcemap.js                       17.27 kB │ gzip:  4.62 kB
ℹ dist/server/metadata-routes.js                           17.19 kB │ gzip:  4.66 kB
ℹ dist/server/app-ssr-stream.js                            16.86 kB │ gzip:  5.41 kB
ℹ dist/plugins/dynamic-preload-metadata.js                 16.32 kB │ gzip:  3.96 kB
ℹ dist/server/pages-page-handler.js                        16.10 kB │ gzip:  4.22 kB
ℹ dist/server/app-page-cache.js                            14.52 kB │ gzip:  3.28 kB
ℹ dist/server/app-page-execution.js                        13.76 kB │ gzip:  4.25 kB
ℹ dist/shims/head.js                                       13.65 kB │ gzip:  4.89 kB
ℹ dist/entries/app-rsc-manifest.js                         13.52 kB │ gzip:  3.02 kB
ℹ dist/server/pages-page-response.js                       13.46 kB │ gzip:  4.44 kB
ℹ dist/server/app-ssr-entry.js                             13.39 kB │ gzip:  4.32 kB
ℹ dist/server/pages-page-data.js                           13.39 kB │ gzip:  3.97 kB
ℹ dist/shims/script.js                                     13.00 kB │ gzip:  4.03 kB
ℹ dist/plugins/import-meta-url.js                          12.53 kB │ gzip:  3.29 kB
ℹ dist/plugins/sass.js                                     12.45 kB │ gzip:  4.76 kB
ℹ dist/server/isr-cache.js                                 12.32 kB │ gzip:  4.45 kB
ℹ dist/shims/font-google-base.js                           12.12 kB │ gzip:  4.06 kB
ℹ dist/server/app-page-boundary-render.js                  11.97 kB │ gzip:  2.88 kB
ℹ dist/server/app-page-probe.js                            11.67 kB │ gzip:  3.83 kB
ℹ dist/shims/form.js                                       11.06 kB │ gzip:  3.51 kB
ℹ dist/server/pages-request-pipeline.js                    10.92 kB │ gzip:  2.97 kB
ℹ dist/server/app-rsc-cache-busting.js                     10.79 kB │ gzip:  2.97 kB
ℹ dist/shims/slot.js                                       10.73 kB │ gzip:  2.92 kB
ℹ dist/server/app-page-head.js                             10.70 kB │ gzip:  2.78 kB
ℹ dist/build/client-build-config.js                        10.50 kB │ gzip:  4.10 kB
ℹ dist/server/app-browser-history-controller.js            10.18 kB │ gzip:  2.51 kB
ℹ dist/server/app-page-element-builder.js                  10.16 kB │ gzip:  3.14 kB
ℹ dist/server/app-browser-visible-commit.js                 9.72 kB │ gzip:  2.23 kB
ℹ dist/shims/error-boundary.js                              9.70 kB │ gzip:  2.05 kB
ℹ dist/server/middleware-runtime.js                         9.64 kB │ gzip:  2.77 kB
ℹ dist/server/app-history-state.js                          9.60 kB │ gzip:  2.29 kB
ℹ dist/typegen.js                                           9.46 kB │ gzip:  2.85 kB
ℹ dist/server/client-reuse-manifest.js                      9.39 kB │ gzip:  2.41 kB
ℹ dist/server/api-handler.js                                9.12 kB │ gzip:  3.23 kB
ℹ dist/build/css-url-assets.js                              8.98 kB │ gzip:  3.46 kB
ℹ dist/server/metadata-route-response.js                    8.92 kB │ gzip:  2.48 kB
ℹ dist/server/app-route-handler-runtime.js                  8.82 kB │ gzip:  2.39 kB
ℹ dist/server/image-optimization.js                         8.71 kB │ gzip:  3.09 kB
ℹ dist/server/app-optimistic-routing.js                     8.69 kB │ gzip:  2.37 kB
ℹ dist/server/app-page-request.js                           8.57 kB │ gzip:  2.19 kB
ℹ dist/init.js                                              8.57 kB │ gzip:  3.07 kB
ℹ dist/build/standalone.js                                  8.41 kB │ gzip:  2.58 kB
ℹ dist/server/socket-error-backstop.js                      8.35 kB │ gzip:  3.49 kB
ℹ dist/build/run-prerender.js                               8.35 kB │ gzip:  3.04 kB
ℹ dist/server/pages-i18n.js                                 8.29 kB │ gzip:  2.92 kB
ℹ dist/plugins/og-assets.js                                 8.25 kB │ gzip:  3.22 kB
ℹ dist/routing/utils.js                                     8.09 kB │ gzip:  3.05 kB
ℹ dist/client/navigation-runtime.js                         8.09 kB │ gzip:  2.08 kB
ℹ dist/server/headers.js                                    7.98 kB │ gzip:  2.88 kB
ℹ dist/server/pages-node-compat.js                          7.96 kB │ gzip:  2.53 kB
ℹ dist/server/static-file-cache.js                          7.80 kB │ gzip:  3.11 kB
ℹ dist/shims/font-local.js                                  7.77 kB │ gzip:  2.69 kB
ℹ dist/server/app-layout-param-observation.js               7.75 kB │ gzip:  1.88 kB
ℹ dist/server/skip-cache-proof.js                           7.73 kB │ gzip:  1.94 kB
ℹ dist/plugins/client-reference-dedup.js                    7.73 kB │ gzip:  2.40 kB
ℹ dist/shims/dynamic.js                                     7.72 kB │ gzip:  2.21 kB
ℹ dist/shims/constants.js                                   7.65 kB │ gzip:  2.38 kB
ℹ dist/routing/route-pattern.js                             7.47 kB │ gzip:  2.10 kB
ℹ dist/utils/project.js                                     7.00 kB │ gzip:  2.40 kB
ℹ dist/entries/pages-client-entry.js                        6.75 kB │ gzip:  2.70 kB
ℹ dist/server/app-middleware.js                             6.70 kB │ gzip:  1.82 kB
ℹ dist/server/app-route-handler-response.js                 6.68 kB │ gzip:  2.22 kB
ℹ dist/server/app-route-handler-dispatch.js                 6.66 kB │ gzip:  1.76 kB
ℹ dist/shims/thenable-params.js                             6.50 kB │ gzip:  1.56 kB
ℹ dist/server/pages-data-route.js                           6.38 kB │ gzip:  2.39 kB
ℹ dist/server/dev-origin-check.js                           6.28 kB │ gzip:  2.24 kB
ℹ dist/server/dev-lockfile.js                               6.23 kB │ gzip:  2.57 kB
ℹ dist/shims/url-utils.js                                   6.20 kB │ gzip:  2.18 kB
ℹ dist/plugins/remove-console.js                            6.13 kB │ gzip:  2.27 kB
ℹ dist/server/app-page-stream.js                            6.08 kB │ gzip:  2.24 kB
ℹ dist/server/app-page-response.js                          5.99 kB │ gzip:  1.51 kB
ℹ dist/build/route-classification-manifest.js               5.96 kB │ gzip:  2.26 kB
ℹ dist/server/app-route-handler-execution.js                5.93 kB │ gzip:  1.61 kB
ℹ dist/server/app-page-boundary.js                          5.88 kB │ gzip:  1.70 kB
ℹ dist/utils/asset-prefix.js                                5.79 kB │ gzip:  2.18 kB
ℹ dist/server/seed-cache.js                                 5.72 kB │ gzip:  2.06 kB
ℹ dist/plugins/require-context.js                           5.68 kB │ gzip:  1.98 kB
ℹ dist/server/metadata-route-build-data.js                  5.67 kB │ gzip:  1.54 kB
ℹ dist/config/tsconfig-paths.js                             5.63 kB │ gzip:  2.04 kB
ℹ dist/routing/pages-router.js                              5.58 kB │ gzip:  1.69 kB
ℹ dist/shims/ppr-fallback-shell.js                          5.58 kB │ gzip:  1.42 kB
ℹ dist/server/pages-document-initial-props.js               5.56 kB │ gzip:  2.19 kB
ℹ dist/server/pages-asset-tags.js                           5.54 kB │ gzip:  2.16 kB
ℹ dist/server/instrumentation.js                            5.52 kB │ gzip:  2.13 kB
ℹ dist/shims/default-global-error.js                        5.51 kB │ gzip:  1.90 kB
ℹ dist/server/app-fallback-renderer.js                      5.46 kB │ gzip:  1.29 kB
ℹ dist/server/prerender-route-params.js                     5.31 kB │ gzip:  1.47 kB
ℹ dist/utils/query.js                                       5.29 kB │ gzip:  1.79 kB
ℹ dist/server/app-rsc-route-matching.js                     5.02 kB │ gzip:  1.55 kB
ℹ dist/routing/route-validation.js                          4.95 kB │ gzip:  1.61 kB
ℹ dist/utils/lazy-chunks.js                                 4.91 kB │ gzip:  1.90 kB
ℹ dist/server/otel-tracer-extension.js                      4.71 kB │ gzip:  1.82 kB
ℹ dist/server/artifact-compatibility.js                     4.64 kB │ gzip:  1.11 kB
ℹ dist/server/middleware.js                                 4.61 kB │ gzip:  1.95 kB
ℹ dist/server/app-segment-config.js                         4.58 kB │ gzip:  1.33 kB
ℹ dist/shims/app-router-scroll.js                           4.57 kB │ gzip:  1.58 kB
ℹ dist/server/app-browser-action-result.js                  4.53 kB │ gzip:  1.61 kB
ℹ dist/routing/file-matcher.js                              4.48 kB │ gzip:  1.75 kB
ℹ dist/server/middleware-matcher.js                         4.42 kB │ gzip:  1.45 kB
ℹ dist/shims/cdn-cache.js                                   4.35 kB │ gzip:  1.86 kB
ℹ dist/build/precompress.js                                 4.32 kB │ gzip:  1.93 kB
ℹ dist/server/app-rsc-request-normalization.js              4.19 kB │ gzip:  1.71 kB
ℹ dist/routing/route-trie.js                                4.15 kB │ gzip:  1.40 kB
ℹ dist/shims/error.js                                       4.05 kB │ gzip:  1.61 kB
ℹ dist/build/layout-classification.js                       3.99 kB │ gzip:  1.60 kB
ℹ dist/shims/font-utils.js                                  3.94 kB │ gzip:  1.52 kB
ℹ dist/cli-args.js                                          3.94 kB │ gzip:  1.37 kB
ℹ dist/utils/client-runtime-metadata.js                     3.87 kB │ gzip:  1.40 kB
ℹ dist/shims/internal/pages-data-target.js                  3.80 kB │ gzip:  1.73 kB
ℹ dist/utils/client-build-manifest.js                       3.80 kB │ gzip:  1.17 kB
ℹ dist/server/app-prerender-endpoints.js                    3.80 kB │ gzip:  1.16 kB
ℹ dist/utils/manifest-paths.js                              3.73 kB │ gzip:  1.25 kB
ℹ dist/server/http-error-responses.js                       3.72 kB │ gzip:  1.45 kB
ℹ dist/server/app-browser-client-reuse-manifest.js          3.71 kB │ gzip:  1.19 kB
ℹ dist/plugins/middleware-server-only.js                    3.67 kB │ gzip:  1.59 kB
ℹ dist/server/app-route-handler-cache.js                    3.65 kB │ gzip:  1.14 kB
ℹ dist/server/worker-utils.js                               3.63 kB │ gzip:  1.35 kB
ℹ dist/build/route-classification-injector.js               3.55 kB │ gzip:  1.18 kB
ℹ dist/server/dev-module-runner.js                          3.53 kB │ gzip:  1.55 kB
ℹ dist/build/ssr-manifest.js                                3.45 kB │ gzip:  1.05 kB
ℹ dist/server/app-route-handler-policy.js                   3.41 kB │ gzip:  1.08 kB
ℹ dist/server/app-prerender-static-params.js                3.40 kB │ gzip:  1.20 kB
ℹ dist/plugins/postcss.js                                   3.39 kB │ gzip:  1.31 kB
ℹ dist/server/pregenerated-concrete-paths.js                3.38 kB │ gzip:  1.30 kB
ℹ dist/build/google-fonts/validate.js                       3.38 kB │ gzip:  1.12 kB
ℹ dist/server/pages-serializable-props.js                   3.37 kB │ gzip:  1.35 kB
ℹ dist/server/server-action-not-found.js                    3.31 kB │ gzip:  1.17 kB
ℹ dist/server/app-ppr-fallback-shell.js                     3.31 kB │ gzip:  1.10 kB
ℹ dist/utils/error-cause.js                                 3.25 kB │ gzip:  1.56 kB
ℹ dist/server/isr-decision.js                               3.25 kB │ gzip:  1.12 kB
ℹ dist/server/app-page-segment-state.js                     3.21 kB │ gzip:  0.86 kB
ℹ dist/server/normalize-path.js                             3.21 kB │ gzip:  1.33 kB
ℹ dist/shims/document.js                                    3.18 kB │ gzip:  1.47 kB
ℹ dist/plugins/server-externals-manifest.js                 3.16 kB │ gzip:  1.43 kB
ℹ dist/build/nitro-route-rules.js                           3.15 kB │ gzip:  1.30 kB
ℹ dist/shims/unified-request-context.js                     3.14 kB │ gzip:  1.29 kB
ℹ dist/shims/image-config.js                                3.14 kB │ gzip:  1.38 kB
ℹ dist/server/app-browser-stream.js                         3.13 kB │ gzip:  1.11 kB
ℹ dist/server/middleware-request-headers.js                 3.13 kB │ gzip:  0.97 kB
ℹ dist/server/client-trace-metadata.js                      3.09 kB │ gzip:  1.33 kB
ℹ dist/server/pages-body-parser-config.js                   3.05 kB │ gzip:  1.34 kB
ℹ dist/shims/url-safety.js                                  3.04 kB │ gzip:  1.41 kB
ℹ dist/server/app-mounted-slots-header.js                   3.03 kB │ gzip:  1.45 kB
ℹ dist/shims/internal/app-route-detection.js                3.02 kB │ gzip:  1.22 kB
ℹ dist/shims/dynamic-preload-chunks.js                      3.00 kB │ gzip:  1.35 kB
ℹ dist/shims/internal/pages-data-fetch-dedup.js             2.99 kB │ gzip:  1.44 kB
ℹ dist/client/instrumentation-client-inject.js              2.98 kB │ gzip:  1.22 kB
ℹ dist/utils/domain-locale.js                               2.94 kB │ gzip:  0.93 kB
ℹ dist/server/pages-api-route.js                            2.92 kB │ gzip:  1.02 kB
ℹ dist/shims/internal/pages-data-url.js                     2.91 kB │ gzip:  1.33 kB
ℹ dist/server/proxy-trust.js                                2.89 kB │ gzip:  1.17 kB
ℹ dist/config/dotenv.js                                     2.87 kB │ gzip:  1.35 kB
ℹ dist/server/cache-control.js                              2.82 kB │ gzip:  1.19 kB
ℹ dist/server/pages-default-404.js                          2.81 kB │ gzip:  1.42 kB
ℹ dist/server/app-rsc-errors.js                             2.76 kB │ gzip:  1.21 kB
ℹ dist/entries/app-browser-entry.js                         2.76 kB │ gzip:  1.05 kB
ℹ dist/plugins/css-data-url.js                              2.75 kB │ gzip:  1.35 kB
ℹ dist/cache/cache-adapters-virtual.js                      2.73 kB │ gzip:  1.08 kB
ℹ dist/server/dev-route-files.js                            2.71 kB │ gzip:  0.94 kB
ℹ dist/server/app-page-render-observation.js                2.69 kB │ gzip:  0.83 kB
ℹ dist/build/assets-ignore.js                               2.61 kB │ gzip:  1.32 kB
ℹ dist/server/navigation-trace.js                           2.60 kB │ gzip:  0.94 kB
ℹ dist/shims/default-not-found.js                           2.58 kB │ gzip:  1.22 kB
ℹ dist/server/app-pages-bridge.js                           2.53 kB │ gzip:  0.94 kB
ℹ dist/shims/cache-for-request.js                           2.42 kB │ gzip:  1.04 kB
ℹ dist/server/app-browser-interception-context.js           2.40 kB │ gzip:  0.70 kB
ℹ dist/plugins/strip-server-exports.js                      2.36 kB │ gzip:  0.99 kB
ℹ dist/server/pages-get-initial-props.js                    2.36 kB │ gzip:  0.76 kB
ℹ dist/plugins/ast-utils.js                                 2.35 kB │ gzip:  0.78 kB
ℹ dist/shims/internal/als-registry.js                       2.33 kB │ gzip:  1.11 kB
ℹ dist/shims/navigation-state.js                            2.31 kB │ gzip:  0.88 kB
ℹ dist/server/app-rsc-response-finalizer.js                 2.25 kB │ gzip:  0.92 kB
ℹ dist/routing/app-router.js                                2.25 kB │ gzip:  0.86 kB
ℹ dist/server/app-browser-rsc-redirect.js                   2.24 kB │ gzip:  0.68 kB
ℹ dist/build/google-fonts/fallback-metrics.js               2.18 kB │ gzip:  0.81 kB
ℹ dist/shims/internal/cookie-serialize.js                   2.16 kB │ gzip:  1.04 kB
ℹ dist/shims/navigation.react-server.js                     2.16 kB │ gzip:  0.59 kB
ℹ dist/server/app-router-entry.js                           2.15 kB │ gzip:  0.85 kB
ℹ dist/server/app-ssr-error-meta.js                         2.11 kB │ gzip:  0.84 kB
ℹ dist/server/app-browser-popstate.js                       2.11 kB │ gzip:  0.75 kB
ℹ dist/server/csp.js                                        2.10 kB │ gzip:  0.71 kB
ℹ dist/utils/text-stream.js                                 2.08 kB │ gzip:  0.92 kB
ℹ dist/server/app-elements.js                               1.98 kB │ gzip:  0.66 kB
ℹ dist/server/app-interception-context-header.js            1.98 kB │ gzip:  1.02 kB
ℹ dist/client/window-next.js                                1.96 kB │ gzip:  0.92 kB
ℹ dist/client/vinext-next-data.js                           1.94 kB │ gzip:  0.77 kB
ℹ dist/server/app-page-render-identity.js                   1.93 kB │ gzip:  0.60 kB
ℹ dist/plugins/rsc-client-reference-loaders.js              1.92 kB │ gzip:  0.85 kB
ℹ dist/utils/hash.js                                        1.92 kB │ gzip:  1.00 kB
ℹ dist/build/inline-css.js                                  1.90 kB │ gzip:  0.79 kB
ℹ dist/server/dev-error-overlay-store.js                    1.89 kB │ gzip:  0.68 kB
ℹ dist/shims/internal/make-hanging-promise.js               1.89 kB │ gzip:  0.82 kB
ℹ dist/server/html.js                                       1.85 kB │ gzip:  0.92 kB
ℹ dist/server/app-client-reference-preloader.js             1.83 kB │ gzip:  0.59 kB
ℹ dist/build/static-export.js                               1.82 kB │ gzip:  0.71 kB
ℹ dist/shims/internal/link-status-registry.js               1.81 kB │ gzip:  0.71 kB
ℹ dist/shims/app.js                                         1.81 kB │ gzip:  0.87 kB
ℹ dist/shims/link-prefetch.js                               1.80 kB │ gzip:  0.74 kB
ℹ dist/server/app-page-params.js                            1.79 kB │ gzip:  0.57 kB
ℹ dist/shims/internal/route-pattern-for-warning.js          1.76 kB │ gzip:  0.88 kB
ℹ dist/shims/request-context.js                             1.76 kB │ gzip:  0.77 kB
ℹ dist/utils/base-path.js                                   1.73 kB │ gzip:  0.75 kB
ℹ dist/plugins/wasm-module-import.js                        1.72 kB │ gzip:  0.88 kB
ℹ dist/build/google-fonts/get-axes.js                       1.69 kB │ gzip:  0.70 kB
ℹ dist/server/request-log.js                                1.69 kB │ gzip:  0.76 kB
ℹ dist/server/app-browser-mpa-navigation.js                 1.68 kB │ gzip:  0.63 kB
ℹ dist/server/implicit-tags.js                              1.67 kB │ gzip:  0.65 kB
ℹ dist/entries/runtime-entry-module.js                      1.66 kB │ gzip:  0.76 kB
ℹ dist/shims/layout-segment-context.js                      1.66 kB │ gzip:  0.76 kB
ℹ dist/utils/encode-cache-tag.js                            1.65 kB │ gzip:  0.93 kB
ℹ dist/plugins/instrumentation-client.js                    1.64 kB │ gzip:  0.69 kB
ℹ dist/shims/unrecognized-action-error.js                   1.63 kB │ gzip:  0.77 kB
ℹ dist/build/next-client-runtime-manifests.js               1.62 kB │ gzip:  0.56 kB
ℹ dist/routing/route-matching.js                            1.60 kB │ gzip:  0.75 kB
ℹ dist/server/server-globals.js                             1.58 kB │ gzip:  0.70 kB
ℹ dist/shims/internal/app-router-context.js                 1.58 kB │ gzip:  0.62 kB
ℹ dist/shims/legacy-image.js                                1.56 kB │ gzip:  0.70 kB
ℹ dist/server/next-error-digest.js                          1.55 kB │ gzip:  0.72 kB
ℹ dist/shims/app-router-scroll-state.js                     1.54 kB │ gzip:  0.49 kB
ℹ dist/server/instrumentation-runtime.js                    1.54 kB │ gzip:  0.72 kB
ℹ dist/server/app-render-dependency.js                      1.53 kB │ gzip:  0.54 kB
ℹ dist/utils/vite-version.js                                1.49 kB │ gzip:  0.75 kB
ℹ dist/shims/router-state.js                                1.48 kB │ gzip:  0.68 kB
ℹ dist/utils/client-entry-manifest.js                       1.46 kB │ gzip:  0.52 kB
ℹ dist/server/app-rsc-render-mode.js                        1.45 kB │ gzip:  0.44 kB
ℹ dist/shims/og.js                                          1.45 kB │ gzip:  0.71 kB
ℹ dist/server/static-layout-client-reuse-proof.js           1.42 kB │ gzip:  0.47 kB
ℹ dist/server/app-inline-css-client.js                      1.42 kB │ gzip:  0.58 kB
ℹ dist/server/middleware-response-headers.js                1.41 kB │ gzip:  0.66 kB
ℹ dist/server/document-initial-head.js                      1.41 kB │ gzip:  0.70 kB
ℹ dist/shims/i18n-context.js                                1.41 kB │ gzip:  0.47 kB
ℹ dist/server/rsc-stream-hints.js                           1.39 kB │ gzip:  0.65 kB
ℹ dist/plugins/async-hooks-stub.js                          1.38 kB │ gzip:  0.70 kB
ℹ dist/server/app-static-generation.js                      1.36 kB │ gzip:  0.62 kB
ℹ dist/shims/i18n-state.js                                  1.34 kB │ gzip:  0.65 kB
ℹ dist/server/app-page-method.js                            1.33 kB │ gzip:  0.53 kB
ℹ dist/shims/head-state.js                                  1.27 kB │ gzip:  0.51 kB
ℹ dist/utils/vinext-root.js                                 1.27 kB │ gzip:  0.62 kB
ℹ dist/shims/hash-scroll.js                                 1.26 kB │ gzip:  0.53 kB
ℹ dist/build/google-fonts/build-url.js                      1.24 kB │ gzip:  0.57 kB
ℹ dist/utils/mdx-scan.js                                    1.21 kB │ gzip:  0.63 kB
ℹ dist/server/app-route-module-loader.js                    1.20 kB │ gzip:  0.54 kB
ℹ dist/server/pages-revalidate.js                           1.19 kB │ gzip:  0.60 kB
ℹ dist/utils/public-routes.js                               1.19 kB │ gzip:  0.53 kB
ℹ dist/shims/root-params.js                                 1.16 kB │ gzip:  0.51 kB
ℹ dist/server/app-rsc-embedded-chunks.js                    1.16 kB │ gzip:  0.53 kB
ℹ dist/server/dev-initial-server-error.js                   1.07 kB │ gzip:  0.51 kB
ℹ dist/server/app-post-middleware-context.js                1.06 kB │ gzip:  0.55 kB
ℹ dist/server/app-request-context.js                        1.06 kB │ gzip:  0.52 kB
ℹ dist/build/clean-output.js                                1.05 kB │ gzip:  0.43 kB
ℹ dist/shims/script-nonce-context.js                        1.05 kB │ gzip:  0.38 kB
ℹ dist/server/prerender-work-unit-setup.js                  1.05 kB │ gzip:  0.57 kB
ℹ dist/plugins/rsc-client-shim-excludes.js                  1.03 kB │ gzip:  0.49 kB
ℹ dist/shims/pages-router-runtime.js                        1.02 kB │ gzip:  0.46 kB
ℹ dist/server/app-browser-hydration.js                      0.99 kB │ gzip:  0.45 kB
ℹ dist/server/default-not-found-module.js                   0.99 kB │ gzip:  0.56 kB
ℹ dist/shims/compat-router.js                               0.97 kB │ gzip:  0.49 kB
ℹ dist/server/default-global-error-module.js                0.97 kB │ gzip:  0.55 kB
ℹ dist/entries/app-ssr-entry.js                             0.95 kB │ gzip:  0.53 kB
ℹ dist/shims/use-merged-ref.js                              0.95 kB │ gzip:  0.37 kB
ℹ dist/server/app-rsc-error-handler.js                      0.91 kB │ gzip:  0.49 kB
ℹ dist/shims/internal/parse-cookie-header.js                0.89 kB │ gzip:  0.52 kB
ℹ dist/server/app-visited-response-cache.js                 0.88 kB │ gzip:  0.39 kB
ℹ dist/utils/path.js                                        0.85 kB │ gzip:  0.53 kB
ℹ dist/client/validate-module-path.js                       0.84 kB │ gzip:  0.47 kB
ℹ dist/shims/readonly-url-search-params.js                  0.83 kB │ gzip:  0.38 kB
ℹ dist/server/app-page-search-params-observation.js         0.82 kB │ gzip:  0.36 kB
ℹ dist/server/pages-media-type.js                           0.82 kB │ gzip:  0.46 kB
ℹ dist/utils/html-limited-bots.js                           0.81 kB │ gzip:  0.48 kB
ℹ dist/server/pages-readiness.js                            0.80 kB │ gzip:  0.36 kB
ℹ dist/build/server-manifest.js                             0.79 kB │ gzip:  0.44 kB
ℹ dist/server/app-browser-error.js                          0.77 kB │ gzip:  0.34 kB
ℹ dist/shims/client-hook-error.js                           0.75 kB │ gzip:  0.41 kB
ℹ dist/shims/internal/work-unit-async-storage.js            0.75 kB │ gzip:  0.41 kB
ℹ dist/client/instrumentation-client-state.js               0.74 kB │ gzip:  0.28 kB
ℹ dist/server/cookie-utils.js                               0.73 kB │ gzip:  0.44 kB
ℹ dist/utils/safe-json-file.js                              0.70 kB │ gzip:  0.45 kB
ℹ dist/utils/prerender-output-paths.js                      0.69 kB │ gzip:  0.33 kB
ℹ dist/server/pages-page-method.js                          0.67 kB │ gzip:  0.37 kB
ℹ dist/shims/client-locale.js                               0.66 kB │ gzip:  0.35 kB
ℹ dist/shims/internal/utils.js                              0.66 kB │ gzip:  0.34 kB
ℹ dist/shims/web-vitals.js                                  0.61 kB │ gzip:  0.28 kB
ℹ dist/server/cache-headers.js                              0.60 kB │ gzip:  0.27 kB
ℹ dist/shims/amp.js                                         0.50 kB │ gzip:  0.30 kB
ℹ dist/shims/config.js                                      0.50 kB │ gzip:  0.29 kB
ℹ dist/utils/navigation-signal.js                           0.48 kB │ gzip:  0.29 kB
ℹ dist/utils/sorted-array.js                                0.48 kB │ gzip:  0.27 kB
ℹ dist/build/google-fonts/sort-variants.js                  0.46 kB │ gzip:  0.25 kB
ℹ dist/server/app-hook-warning-suppression.js               0.46 kB │ gzip:  0.29 kB
ℹ dist/utils/cache-control-metadata.js                      0.45 kB │ gzip:  0.25 kB
ℹ dist/client/instrumentation-client.js                     0.43 kB │ gzip:  0.18 kB
ℹ dist/shims/offline.js                                     0.43 kB │ gzip:  0.30 kB
ℹ dist/client/pages-router-link-navigation.js               0.42 kB │ gzip:  0.24 kB
ℹ dist/server/streaming-metadata.js                         0.34 kB │ gzip:  0.21 kB
ℹ dist/shims/internal/router-context.js                     0.33 kB │ gzip:  0.22 kB
ℹ dist/shims/before-interactive-context.js                  0.31 kB │ gzip:  0.18 kB
ℹ dist/shims/font-google.js                                 0.28 kB │ gzip:  0.15 kB
ℹ dist/utils/promise.js                                     0.24 kB │ gzip:  0.17 kB
ℹ dist/utils/number.js                                      0.20 kB │ gzip:  0.15 kB
ℹ dist/server/dev-stack-sourcemap-endpoint.js               0.19 kB │ gzip:  0.16 kB
ℹ dist/build/google-fonts/font-metadata.js                  0.19 kB │ gzip:  0.14 kB
ℹ dist/utils/compare.js                                     0.19 kB │ gzip:  0.14 kB
ℹ dist/server/app-bfcache-id.js                             0.18 kB │ gzip:  0.13 kB
ℹ dist/server/edge-api-runtime.js                           0.18 kB │ gzip:  0.15 kB
ℹ dist/utils/record.js                                      0.18 kB │ gzip:  0.16 kB
ℹ dist/utils/dev-error-recovery-event.js                    0.17 kB │ gzip:  0.14 kB
ℹ dist/utils/regex.js                                       0.15 kB │ gzip:  0.15 kB
ℹ dist/cloudflare/index.js                                  0.14 kB │ gzip:  0.12 kB
ℹ dist/shims/internal/cookies.js                            0.11 kB │ gzip:  0.08 kB
ℹ dist/cache.js                                             0.09 kB │ gzip:  0.08 kB
ℹ dist/entries/pages-entry-helpers.js                       0.09 kB │ gzip:  0.09 kB
ℹ dist/build/layout-classification-types.js                 0.01 kB │ gzip:  0.03 kB
ℹ dist/client/empty-module.js                               0.01 kB │ gzip:  0.03 kB
ℹ dist/shims/client-only.js                                 0.01 kB │ gzip:  0.03 kB
ℹ dist/shims/internal/api-utils.js                          0.01 kB │ gzip:  0.03 kB
ℹ dist/shims/request-state-types.js                         0.01 kB │ gzip:  0.03 kB
ℹ dist/shims/server-only.js                                 0.01 kB │ gzip:  0.03 kB
ℹ dist/build/google-fonts/font-data.js                    358.51 kB │ gzip: 24.18 kB
ℹ dist/build/google-fonts/fallback-metrics-data.js        103.01 kB │ gzip: 23.28 kB
ℹ dist/cloudflare/src/cache/kv-data-adapter.runtime.js     15.65 kB │ gzip:  5.30 kB
ℹ dist/cloudflare/src/cache/cdn-adapter.runtime.js          4.23 kB │ gzip:  1.96 kB
ℹ dist/cloudflare/src/utils/cache-control-metadata.js       0.82 kB │ gzip:  0.42 kB
ℹ dist/shims/navigation.d.ts                               28.82 kB │ gzip:  8.69 kB
ℹ dist/config/next-config.d.ts                             23.30 kB │ gzip:  8.14 kB
ℹ dist/server/cache-proof.d.ts                             16.27 kB │ gzip:  3.06 kB
ℹ dist/shims/cache.d.ts                                    15.81 kB │ gzip:  5.09 kB
ℹ dist/routing/app-route-graph.d.ts                        15.25 kB │ gzip:  4.52 kB
ℹ dist/config/config-matchers.d.ts                         12.18 kB │ gzip:  4.64 kB
ℹ dist/server/request-pipeline.d.ts                        11.14 kB │ gzip:  4.08 kB
ℹ dist/shims/headers.d.ts                                  11.11 kB │ gzip:  3.91 kB
ℹ dist/server/app-server-action-execution.d.ts             10.63 kB │ gzip:  3.33 kB
ℹ dist/shims/server.d.ts                                   10.54 kB │ gzip:  3.45 kB
ℹ dist/server/app-elements-wire.d.ts                        9.41 kB │ gzip:  2.53 kB
ℹ dist/server/pages-page-data.d.ts                          8.87 kB │ gzip:  3.05 kB
ℹ dist/shims/metadata.d.ts                                  8.62 kB │ gzip:  2.51 kB
ℹ dist/deploy.d.ts                                          8.54 kB │ gzip:  3.07 kB
ℹ dist/server/prod-server.d.ts                              8.47 kB │ gzip:  3.41 kB
ℹ dist/build/prerender.d.ts                                 8.13 kB │ gzip:  3.08 kB
ℹ dist/server/app-page-dispatch.d.ts                        8.07 kB │ gzip:  2.43 kB
ℹ dist/shims/router.d.ts                                    8.04 kB │ gzip:  2.77 kB
ℹ dist/build/client-build-config.d.ts                       7.81 kB │ gzip:  2.96 kB
ℹ dist/server/app-page-route-wiring.d.ts                    7.81 kB │ gzip:  2.11 kB
ℹ dist/server/navigation-planner.d.ts                       7.79 kB │ gzip:  1.99 kB
ℹ dist/server/headers.d.ts                                  7.73 kB │ gzip:  2.76 kB
ℹ dist/shims/constants.d.ts                                 7.54 kB │ gzip:  2.10 kB
ℹ dist/server/app-browser-state.d.ts                        7.37 kB │ gzip:  1.76 kB
ℹ dist/server/app-page-stream.d.ts                          7.26 kB │ gzip:  2.36 kB
ℹ dist/server/app-page-request.d.ts                         7.20 kB │ gzip:  1.57 kB
ℹ dist/client/window-next.d.ts                              7.12 kB │ gzip:  2.64 kB
ℹ dist/server/app-page-execution.d.ts                       6.96 kB │ gzip:  2.67 kB
ℹ dist/server/app-rsc-handler.d.ts                          6.86 kB │ gzip:  2.12 kB
ℹ dist/server/isr-cache.d.ts                                6.67 kB │ gzip:  2.56 kB
ℹ dist/server/app-page-probe.d.ts                           6.66 kB │ gzip:  2.57 kB
ℹ dist/shims/error-boundary.d.ts                            6.37 kB │ gzip:  1.16 kB
ℹ dist/server/pages-page-response.d.ts                      6.24 kB │ gzip:  2.54 kB
ℹ dist/server/client-reuse-manifest.d.ts                    6.04 kB │ gzip:  1.49 kB
ℹ dist/shims/fetch-cache.d.ts                               6.03 kB │ gzip:  2.26 kB
ℹ dist/server/app-page-boundary.d.ts                        5.88 kB │ gzip:  1.41 kB
ℹ dist/build/report.d.ts                                    5.77 kB │ gzip:  2.23 kB
ℹ dist/server/app-page-cache.d.ts                           5.63 kB │ gzip:  1.42 kB
ℹ dist/server/app-page-element-builder.d.ts                 5.59 kB │ gzip:  1.81 kB
ℹ dist/server/image-optimization.d.ts                       5.56 kB │ gzip:  2.22 kB
ℹ dist/server/pages-data-route.d.ts                         5.54 kB │ gzip:  2.08 kB
ℹ dist/shims/cdn-cache.d.ts                                 5.48 kB │ gzip:  2.17 kB
ℹ dist/server/pages-page-handler.d.ts                       5.41 kB │ gzip:  1.94 kB
ℹ dist/server/app-browser-history-controller.d.ts           5.35 kB │ gzip:  1.78 kB
ℹ dist/server/metadata-routes.d.ts                          5.34 kB │ gzip:  1.78 kB
ℹ dist/server/app-fallback-renderer.d.ts                    5.30 kB │ gzip:  1.80 kB
ℹ dist/server/app-browser-navigation-controller.d.ts        5.21 kB │ gzip:  1.60 kB
ℹ dist/plugins/fonts.d.ts                                   5.19 kB │ gzip:  2.31 kB
ℹ dist/server/pages-request-pipeline.d.ts                   5.05 kB │ gzip:  1.86 kB
ℹ dist/shims/link.d.ts                                      5.01 kB │ gzip:  1.52 kB
ℹ dist/utils/asset-prefix.d.ts                              5.00 kB │ gzip:  1.93 kB
ℹ dist/server/dev-lockfile.d.ts                             4.90 kB │ gzip:  2.01 kB
ℹ dist/server/app-page-render.d.ts                          4.84 kB │ gzip:  1.63 kB
ℹ dist/server/pages-document-initial-props.d.ts             4.76 kB │ gzip:  1.68 kB
ℹ dist/server/pages-i18n.d.ts                               4.73 kB │ gzip:  1.83 kB
ℹ dist/routing/utils.d.ts                                   4.59 kB │ gzip:  1.83 kB
ℹ dist/index.d.ts                                           4.54 kB │ gzip:  1.83 kB
ℹ dist/entries/app-rsc-entry.d.ts                           4.36 kB │ gzip:  1.97 kB
ℹ dist/server/app-page-boundary-render.d.ts                 4.31 kB │ gzip:  1.41 kB
ℹ dist/client/navigation-runtime.d.ts                       4.29 kB │ gzip:  1.51 kB
ℹ dist/server/http-error-responses.d.ts                     4.18 kB │ gzip:  1.73 kB
ℹ dist/shims/cache-runtime.d.ts                             4.13 kB │ gzip:  1.77 kB
ℹ dist/server/app-history-state.d.ts                        3.97 kB │ gzip:  1.14 kB
ℹ dist/shims/document.d.ts                                  3.94 kB │ gzip:  1.66 kB
ℹ dist/server/app-rsc-cache-busting.d.ts                    3.86 kB │ gzip:  1.27 kB
ℹ dist/shims/unified-request-context.d.ts                   3.82 kB │ gzip:  1.40 kB
ℹ dist/server/instrumentation.d.ts                          3.79 kB │ gzip:  1.48 kB
ℹ dist/server/isr-decision.d.ts                             3.79 kB │ gzip:  1.47 kB
ℹ dist/check.d.ts                                           3.72 kB │ gzip:  1.69 kB
ℹ dist/server/app-route-handler-execution.d.ts              3.71 kB │ gzip:  1.30 kB
ℹ dist/server/pages-asset-tags.d.ts                         3.70 kB │ gzip:  1.57 kB
ℹ dist/shims/head.d.ts                                      3.69 kB │ gzip:  1.65 kB
ℹ dist/server/middleware.d.ts                               3.67 kB │ gzip:  1.56 kB
ℹ dist/server/navigation-trace.d.ts                         3.56 kB │ gzip:  1.15 kB
ℹ dist/cloudflare/tpr.d.ts                                  3.43 kB │ gzip:  1.59 kB
ℹ dist/server/app-ssr-stream.d.ts                           3.33 kB │ gzip:  1.41 kB
ℹ dist/server/pages-api-route.d.ts                          3.31 kB │ gzip:  1.43 kB
ℹ dist/init.d.ts                                            3.31 kB │ gzip:  1.46 kB
ℹ dist/server/artifact-compatibility.d.ts                   3.28 kB │ gzip:  0.76 kB
ℹ dist/server/app-rsc-request-normalization.d.ts            3.27 kB │ gzip:  1.46 kB
ℹ dist/shims/font-google-base.d.ts                          3.22 kB │ gzip:  1.35 kB
ℹ dist/server/app-rsc-route-matching.d.ts                   3.21 kB │ gzip:  1.18 kB
ℹ dist/routing/route-pattern.d.ts                           3.20 kB │ gzip:  1.20 kB
ℹ dist/server/app-browser-visible-commit.d.ts               3.17 kB │ gzip:  0.86 kB
ℹ dist/server/skip-cache-proof.d.ts                         3.13 kB │ gzip:  0.78 kB
ℹ dist/utils/lazy-chunks.d.ts                               3.02 kB │ gzip:  1.33 kB
ℹ dist/server/middleware-runtime.d.ts                       3.02 kB │ gzip:  1.23 kB
ℹ dist/shims/internal/pages-data-target.d.ts                3.01 kB │ gzip:  1.44 kB
ℹ dist/server/app-browser-action-result.d.ts                3.00 kB │ gzip:  0.96 kB
ℹ dist/plugins/sass.d.ts                                    3.00 kB │ gzip:  1.39 kB
ℹ dist/build/layout-classification.d.ts                     2.95 kB │ gzip:  1.16 kB
ℹ dist/server/app-page-response.d.ts                        2.94 kB │ gzip:  0.99 kB
ℹ dist/server/app-page-head.d.ts                            2.89 kB │ gzip:  0.83 kB
ℹ dist/utils/project.d.ts                                   2.88 kB │ gzip:  1.25 kB
ℹ dist/server/dev-origin-check.d.ts                         2.86 kB │ gzip:  1.20 kB
ℹ dist/build/route-classification-manifest.d.ts             2.85 kB │ gzip:  1.21 kB
ℹ dist/shims/internal/pages-data-fetch-dedup.d.ts           2.72 kB │ gzip:  1.33 kB
ℹ dist/server/pages-default-404.d.ts                        2.72 kB │ gzip:  1.34 kB
ℹ dist/shims/url-utils.d.ts                                 2.69 kB │ gzip:  1.06 kB
ℹ dist/utils/query.d.ts                                     2.64 kB │ gzip:  1.17 kB
ℹ dist/plugins/middleware-server-only.d.ts                  2.63 kB │ gzip:  1.23 kB
ℹ dist/server/dev-server.d.ts                               2.61 kB │ gzip:  1.21 kB
ℹ dist/server/static-file-cache.d.ts                        2.60 kB │ gzip:  1.23 kB
ℹ dist/cache/cache-adapters-virtual.d.ts                    2.59 kB │ gzip:  1.14 kB
ℹ dist/shims/font-utils.d.ts                                2.57 kB │ gzip:  1.01 kB
ℹ dist/routing/file-matcher.d.ts                            2.54 kB │ gzip:  1.04 kB
ℹ dist/server/app-route-handler-policy.d.ts                 2.52 kB │ gzip:  0.72 kB
ℹ dist/server/app-route-handler-runtime.d.ts                2.45 kB │ gzip:  0.99 kB
ℹ dist/server/pages-body-parser-config.d.ts                 2.41 kB │ gzip:  1.14 kB
ℹ dist/server/app-layout-param-observation.d.ts             2.40 kB │ gzip:  0.81 kB
ℹ dist/entries/app-rsc-manifest.d.ts                        2.40 kB │ gzip:  1.09 kB
ℹ dist/shims/request-context.d.ts                           2.37 kB │ gzip:  1.02 kB
ℹ dist/server/app-route-module-loader.d.ts                  2.36 kB │ gzip:  1.07 kB
ℹ dist/server/dev-error-overlay.d.ts                        2.32 kB │ gzip:  0.76 kB
ℹ dist/server/pages-node-compat.d.ts                        2.29 kB │ gzip:  0.91 kB
ℹ dist/plugins/og-assets.d.ts                               2.29 kB │ gzip:  1.11 kB
ℹ dist/server/otel-tracer-extension.d.ts                    2.28 kB │ gzip:  1.03 kB
ℹ dist/routing/route-trie.d.ts                              2.26 kB │ gzip:  1.07 kB
ℹ dist/shims/slot.d.ts                                      2.25 kB │ gzip:  0.81 kB
ℹ dist/server/app-route-handler-cache.d.ts                  2.23 kB │ gzip:  0.79 kB
ℹ dist/server/instrumentation-runtime.d.ts                  2.22 kB │ gzip:  1.08 kB
ℹ dist/server/cache-control.d.ts                            2.20 kB │ gzip:  1.03 kB
ℹ dist/shims/internal/link-status-registry.d.ts             2.19 kB │ gzip:  0.95 kB
ℹ dist/server/app-pages-bridge.d.ts                         2.16 kB │ gzip:  0.95 kB
ℹ dist/build/nitro-route-rules.d.ts                         2.14 kB │ gzip:  0.95 kB
ℹ dist/shims/internal/pages-data-url.d.ts                   2.14 kB │ gzip:  0.98 kB
ℹ dist/build/run-prerender.d.ts                             2.13 kB │ gzip:  1.00 kB
ℹ dist/config/dotenv.d.ts                                   2.13 kB │ gzip:  1.10 kB
ℹ dist/server/app-ssr-entry.d.ts                            2.12 kB │ gzip:  1.07 kB
ℹ dist/routing/pages-router.d.ts                            2.04 kB │ gzip:  0.85 kB
ℹ dist/server/app-optimistic-routing.d.ts                   2.02 kB │ gzip:  0.53 kB
ℹ dist/server/app-route-handler-dispatch.d.ts               2.02 kB │ gzip:  0.79 kB
ℹ dist/server/app-mounted-slots-header.d.ts                 2.02 kB │ gzip:  1.06 kB
ℹ dist/shims/cache-for-request.d.ts                         2.01 kB │ gzip:  0.88 kB
ℹ dist/build/static-export.d.ts                             1.99 kB │ gzip:  0.75 kB
ℹ dist/server/app-elements.d.ts                             1.98 kB │ gzip:  0.60 kB
ℹ dist/shims/internal/cookie-serialize.d.ts                 1.97 kB │ gzip:  0.95 kB
ℹ dist/build/layout-classification-types.d.ts               1.96 kB │ gzip:  0.86 kB
ℹ dist/client/instrumentation-client-inject.d.ts            1.95 kB │ gzip:  0.89 kB
ℹ dist/server/next-error-digest.d.ts                        1.94 kB │ gzip:  0.89 kB
ℹ dist/server/normalize-path.d.ts                           1.91 kB │ gzip:  0.90 kB
ℹ dist/plugins/optimize-imports.d.ts                        1.91 kB │ gzip:  0.93 kB
ℹ dist/utils/client-runtime-metadata.d.ts                   1.91 kB │ gzip:  0.90 kB
ℹ dist/shims/script.d.ts                                    1.86 kB │ gzip:  0.88 kB
ℹ dist/shims/navigation.react-server.d.ts                   1.86 kB │ gzip:  0.54 kB
ℹ dist/server/pregenerated-concrete-paths.d.ts              1.81 kB │ gzip:  0.82 kB
ℹ dist/shims/image.d.ts                                     1.81 kB │ gzip:  0.83 kB
ℹ dist/shims/image-config.d.ts                              1.80 kB │ gzip:  0.87 kB
ℹ dist/shims/internal/app-route-detection.d.ts              1.80 kB │ gzip:  0.92 kB
ℹ dist/shims/ppr-fallback-shell.d.ts                        1.80 kB │ gzip:  0.55 kB
ℹ dist/shims/url-safety.d.ts                                1.79 kB │ gzip:  0.90 kB
ℹ dist/server/dev-stack-sourcemap.d.ts                      1.77 kB │ gzip:  0.62 kB
ℹ dist/server/app-middleware.d.ts                           1.77 kB │ gzip:  0.72 kB
ℹ dist/utils/manifest-paths.d.ts                            1.76 kB │ gzip:  0.82 kB
ℹ dist/server/socket-error-backstop.d.ts                    1.76 kB │ gzip:  0.91 kB
ℹ dist/server/prerender-route-params.d.ts                   1.76 kB │ gzip:  0.47 kB
ℹ dist/server/proxy-trust.d.ts                              1.73 kB │ gzip:  0.84 kB
ℹ dist/build/assets-ignore.d.ts                             1.72 kB │ gzip:  0.92 kB
ℹ dist/server/app-segment-config.d.ts                       1.68 kB │ gzip:  0.66 kB
ℹ dist/server/pages-page-method.d.ts                        1.67 kB │ gzip:  0.85 kB
ℹ dist/server/app-interception-context-header.d.ts          1.65 kB │ gzip:  0.91 kB
ℹ dist/server/app-route-handler-response.d.ts               1.62 kB │ gzip:  0.52 kB
ℹ dist/shims/unrecognized-action-error.d.ts                 1.58 kB │ gzip:  0.74 kB
ℹ dist/shims/before-interactive-context.d.ts                1.56 kB │ gzip:  0.71 kB
ℹ dist/plugins/client-reference-dedup.d.ts                  1.55 kB │ gzip:  0.74 kB
ℹ dist/server/app-rsc-response-finalizer.d.ts               1.54 kB │ gzip:  0.78 kB
ℹ dist/server/app-page-render-observation.d.ts              1.54 kB │ gzip:  0.50 kB
ℹ dist/shims/link-prefetch.d.ts                             1.53 kB │ gzip:  0.54 kB
ℹ dist/server/pages-readiness.d.ts                          1.51 kB │ gzip:  0.77 kB
ℹ dist/utils/encode-cache-tag.d.ts                          1.49 kB │ gzip:  0.86 kB
ℹ dist/server/dev-error-overlay-store.d.ts                  1.49 kB │ gzip:  0.53 kB
ℹ dist/server/client-trace-metadata.d.ts                    1.48 kB │ gzip:  0.63 kB
ℹ dist/server/app-prerender-static-params.d.ts              1.46 kB │ gzip:  0.67 kB
ℹ dist/build/css-url-assets.d.ts                            1.46 kB │ gzip:  0.77 kB
ℹ dist/server/file-based-metadata.d.ts                      1.45 kB │ gzip:  0.66 kB
ℹ dist/server/app-browser-hydration.d.ts                    1.43 kB │ gzip:  0.51 kB
ℹ dist/server/html.d.ts                                     1.41 kB │ gzip:  0.71 kB
ℹ dist/client/vinext-next-data.d.ts                         1.39 kB │ gzip:  0.62 kB
ℹ dist/shims/internal/route-pattern-for-warning.d.ts        1.39 kB │ gzip:  0.73 kB
ℹ dist/utils/text-stream.d.ts                               1.37 kB │ gzip:  0.73 kB
ℹ dist/shims/internal/work-unit-async-storage.d.ts          1.37 kB │ gzip:  0.55 kB
ℹ dist/utils/base-path.d.ts                                 1.36 kB │ gzip:  0.60 kB
ℹ dist/utils/domain-locale.d.ts                             1.35 kB │ gzip:  0.57 kB
ℹ dist/shims/internal/utils.d.ts                            1.34 kB │ gzip:  0.61 kB
ℹ dist/build/precompress.d.ts                               1.33 kB │ gzip:  0.68 kB
ℹ dist/routing/app-router.d.ts                              1.31 kB │ gzip:  0.55 kB
ℹ dist/server/server-action-not-found.d.ts                  1.31 kB │ gzip:  0.59 kB
ℹ dist/server/app-browser-popstate.d.ts                     1.31 kB │ gzip:  0.48 kB
ℹ dist/server/app-browser-stream.d.ts                       1.30 kB │ gzip:  0.60 kB
ℹ dist/shims/font-local.d.ts                                1.29 kB │ gzip:  0.59 kB
ℹ dist/shims/internal/app-router-context.d.ts               1.24 kB │ gzip:  0.47 kB
ℹ dist/shims/legacy-image.d.ts                              1.24 kB │ gzip:  0.55 kB
ℹ dist/shims/layout-segment-context.d.ts                    1.24 kB │ gzip:  0.55 kB
ℹ dist/server/app-browser-rsc-redirect.d.ts                 1.23 kB │ gzip:  0.41 kB
ℹ dist/shims/default-global-error.d.ts                      1.22 kB │ gzip:  0.66 kB
ℹ dist/server/seed-cache.d.ts                               1.22 kB │ gzip:  0.64 kB
ℹ dist/server/app-browser-interception-context.d.ts         1.21 kB │ gzip:  0.51 kB
ℹ dist/shims/app.d.ts                                       1.20 kB │ gzip:  0.50 kB
ℹ dist/build/route-classification-injector.d.ts             1.19 kB │ gzip:  0.55 kB
ℹ dist/shims/navigation-state.d.ts                          1.19 kB │ gzip:  0.50 kB
ℹ dist/server/dev-module-runner.d.ts                        1.18 kB │ gzip:  0.62 kB
ℹ dist/utils/hash.d.ts                                      1.17 kB │ gzip:  0.65 kB
ℹ dist/plugins/postcss.d.ts                                 1.17 kB │ gzip:  0.61 kB
ℹ dist/shims/dynamic.d.ts                                   1.17 kB │ gzip:  0.54 kB
ℹ dist/server/pages-serializable-props.d.ts                 1.13 kB │ gzip:  0.56 kB
ℹ dist/entries/runtime-entry-module.d.ts                    1.13 kB │ gzip:  0.58 kB
ℹ dist/cli-args.d.ts                                        1.12 kB │ gzip:  0.57 kB
ℹ dist/entries/app-browser-entry.d.ts                       1.10 kB │ gzip:  0.58 kB
ℹ dist/plugins/server-externals-manifest.d.ts               1.09 kB │ gzip:  0.61 kB
ℹ dist/utils/vinext-root.d.ts                               1.07 kB │ gzip:  0.53 kB
ℹ dist/server/app-rsc-errors.d.ts                           1.05 kB │ gzip:  0.45 kB
ℹ dist/build/standalone.d.ts                                1.05 kB │ gzip:  0.53 kB
ℹ dist/utils/client-build-manifest.d.ts                     1.04 kB │ gzip:  0.30 kB
ℹ dist/server/app-rsc-render-mode.d.ts                      1.03 kB │ gzip:  0.38 kB
ℹ dist/server/metadata-route-build-data.d.ts                1.02 kB │ gzip:  0.41 kB
ℹ dist/shims/router-state.d.ts                              1.01 kB │ gzip:  0.53 kB
ℹ dist/shims/form.d.ts                                      0.99 kB │ gzip:  0.56 kB
ℹ dist/server/app-visited-response-cache.d.ts               0.97 kB │ gzip:  0.38 kB
ℹ dist/shims/error.d.ts                                     0.97 kB │ gzip:  0.53 kB
ℹ dist/server/app-render-dependency.d.ts                    0.97 kB │ gzip:  0.35 kB
ℹ dist/server/request-log.d.ts                              0.97 kB │ gzip:  0.53 kB
ℹ dist/server/default-not-found-module.d.ts                 0.94 kB │ gzip:  0.56 kB
ℹ dist/server/app-ppr-fallback-shell.d.ts                   0.94 kB │ gzip:  0.32 kB
ℹ dist/shims/config.d.ts                                    0.94 kB │ gzip:  0.45 kB
ℹ dist/routing/route-matching.d.ts                          0.93 kB │ gzip:  0.49 kB
ℹ dist/server/default-global-error-module.d.ts              0.92 kB │ gzip:  0.55 kB
ℹ dist/shims/request-state-types.d.ts                       0.89 kB │ gzip:  0.29 kB
ℹ dist/server/app-request-context.d.ts                      0.88 kB │ gzip:  0.48 kB
ℹ dist/server/app-page-render-identity.d.ts                 0.87 kB │ gzip:  0.33 kB
ℹ dist/shims/app-router-scroll-state.d.ts                   0.86 kB │ gzip:  0.28 kB
ℹ dist/plugins/ast-utils.d.ts                               0.85 kB │ gzip:  0.37 kB
ℹ dist/shims/thenable-params.d.ts                           0.84 kB │ gzip:  0.45 kB
ℹ dist/config/tsconfig-paths.d.ts                           0.84 kB │ gzip:  0.43 kB
ℹ dist/server/static-layout-client-reuse-proof.d.ts         0.83 kB │ gzip:  0.31 kB
ℹ dist/server/app-rsc-error-handler.d.ts                    0.82 kB │ gzip:  0.46 kB
ℹ dist/server/app-static-generation.d.ts                    0.78 kB │ gzip:  0.31 kB
ℹ dist/plugins/async-hooks-stub.d.ts                        0.78 kB │ gzip:  0.45 kB
ℹ dist/utils/client-entry-manifest.d.ts                     0.78 kB │ gzip:  0.29 kB
ℹ dist/server/app-prerender-endpoints.d.ts                  0.77 kB │ gzip:  0.38 kB
ℹ dist/server/csp.d.ts                                      0.76 kB │ gzip:  0.26 kB
ℹ dist/shims/root-params.…
2026-06-12 11:48:04 +01:00
James Anderson ae5c72ec13 fix(shims): match next/error RSC diagnostic (#1939)
* fix(shims): match next error RSC diagnostic

* test(app-router): run catch-error e2e in CI

* revert: avoid dedicated catch-error CI job
2026-06-12 10:46:46 +00:00
Nathan Nguyen 5ac620c2d0 fix(cache): honor fetch opt-outs and force-dynamic revalidate parity (#1907)
* fix(cache): honor fetch opt-outs in app page output

App Router fetches that explicitly opt out of caching could still leave the rendered page eligible for static output, while dynamic = "force-dynamic" was lowered to fetchCache = "force-no-store" and overrode explicit per-fetch cache/revalidate options.

The cache decision was conflating route-level dynamic rendering with a hard segment fetchCache mode. Next.js treats force-dynamic as a default no-store mode only for fetches without explicit cache or revalidate config, and marks explicit uncached fetches as dynamic for the surrounding render.

Mark explicit uncached fetch decisions through the existing dynamic usage signal, keep force-dynamic as a separate per-request fetch default, and preserve Response.url when reconstructing cached fetch responses.

* fix(cache): correct revalidate:false and Response.url semantics

- Split revalidate: false out of the no-store path; it now caches
  indefinitely (INFINITE_CACHE) matching upstream patch-fetch.ts.
- Store actual response.url (freshResp.url / response.url) in cached
  fetch entries instead of the input request URL.
- Remove markUncachedFetchForPageOutput() from the auth-header fallback
  so it matches upstream's autoNoCache path and does not mark pages
  dynamic.
- Update tests to reflect correct revalidate: false caching behavior
  and add a test for redirect-style response URLs.

* fix(app-router): resolve target route dynamic config during intercepts and revalidation

Prevents the outer route's force-dynamic default from leaking into
interception source routes and ISR revalidation targets.

- app-rsc-entry.ts: expose __resolveRouteDynamicConfig
- app-page-dispatch.ts: pass resolveRouteDynamicConfig to dispatch,
  sync currentForceDynamicFetchDefault when the render target changes
- app-page-dispatch.test.ts: 4 tests covering intercept + revalidation
  paths for both lost and leaked defaults

* fix(app-router): sync fetchCache and force-dynamic default during action redirects/re-renders

* fix(cache): treat revalidate:false as non-explicit for force-dynamic parity

Upstream patch-fetch.ts computes noFetchConfigAndForceDynamic using
!currentFetchRevalidate (truthiness), so revalidate: false is treated
as 'no fetch revalidate config' and force-dynamic wins. vinext's
hasExplicitRevalidateValue() previously returned true for false,
blocking the force-dynamic no-store default and causing the fetch to
cache for 1 year instead.

Update hasExplicitRevalidateValue to exclude false (and 0) from the
explicit set, aligning with upstream's truthiness check. Add a parity
test covering force-dynamic + next.revalidate: false.

* fix(cache): split revalidate predicates for force-dynamic vs segment defaults

The previous fix to hasExplicitRevalidateValue() treated false and 0 as
non-explicit, which matched upstream's force-dynamic truthiness check
but broke segment cache defaults: default-cache would override
revalidate: 0 to force-cache, and default-no-store would override
revalidate: false to no-store.

Split into two helpers:
- hasExplicitRevalidateValue(): any defined value is explicit (for
  segment defaults where 0 and false are explicit opt-outs)
- isFalsyRevalidate(): false and 0 are falsy (for force-dynamic's
  noFetchConfigAndForceDynamic parity check)

Add parity tests for default-cache + revalidate: 0 and
default-no-store + revalidate: false.

* refactor(cache): extract ONE_YEAR_SECONDS and cover only-no-store revalidate:false

* fix(cache): keep dynamic fetch observations for auth bypass and cache-key fallback

Restore recordDynamicFetchObservation in the auth-header safety bypass so
auth-keyed fetches still downgrade the page output to fresh render, and
revert the cache-key-generation fallback to a plain observation so an
internal limitation (oversized/unserializable body) does not mark the
whole page dynamic. Lock in force-dynamic vs explicit segment fetchCache
precedence with a test.

* docs(cache): note deliberate no-cache dynamic-marking divergence from upstream

* fix(route-handler): apply segment fetchCache and force-dynamic fetch default to route handler dispatch

Route handlers never called setCurrentFetchCacheMode /
setCurrentForceDynamicFetchDefault, so a force-dynamic route handler did
not get the per-request no-store fetch default that page dispatch applies,
and an explicit fetchCache export on a route handler module was ignored.

Upstream's app-route module copies userland.fetchCache into the work store
and sets workStore.forceDynamic for dynamic = "force-dynamic", which
patch-fetch turns into a no-store default for fetches without explicit
cache config — for route handlers as well as pages. Mirror that in
dispatchAppRouteHandler and re-apply the state inside the background
regeneration request context.

* fix(fetch-cache): tolerate cached entries missing url and document revalidate:false cacheability

* fix(fetch-cache): fall back to the request URL for cached entries missing url

Reconstructing Response.url from the fetch input preserves the
pre-existing guarantee for legacy/foreign cache entries instead of
degrading to "". Also document why the intercept dispatch deliberately
does not save/restore fetch defaults around buildPageElement.

* docs(fetch-cache): note cached responses now join body-stream cleanup

* docs(fetch-cache): note explicit segment fetchCache beats force-dynamic default

* test(fetch-cache): pin tags-only fetch to no-store under force-dynamic

* docs(fetch-cache): document auth-bypass precedence and test no-store + auth

- Note at the auth-safety bypass that explicit no-store/no-cache/revalidate: 0
  takes the stronger branch first and fully marks the page dynamic; the bypass
  only covers implicitly-cacheable auth-keyed fetches.
- Add a test locking in that explicit no-store with auth headers routes through
  markUncachedFetchForPageOutput rather than the softer auth bypass.
- Clarify in dispatchAppRouteHandler that the fetch-cache setters are new
  wiring for route handlers, not a mirror of a pre-existing pattern.

* test(route-handler): lock no-store fetch bailing ISR for revalidating handlers

A route handler with revalidate = 60 that performs
fetch(url, { cache: "no-store" }) must skip its ISR cache write and be
marked known-dynamic, now that the patched fetch's explicit no-store
branch calls markDynamicUsage() (upstream patch-fetch parity). Exercises
the real fetch-cache shim and the real headers-shim dynamic-usage pair,
matching the app-route-handler-dispatch wiring.

---------

Co-authored-by: James <james@eli.cx>
2026-06-12 11:44:28 +01:00
James Anderson e9b0f68658 feat(web): expose latest compatibility failures (#1941) 2026-06-12 10:37:54 +00:00
Nathan Nguyen e018a08708 fix(pages-router): restore scroll across reload history traversal (#1905)
* fix(pages-router): restore scroll across reload history traversal

Pages Router pages with experimental.scrollRestoration currently expose window.next.router before the popstate runtime is installed and only keep Vinext scroll coordinates in the in-memory history state. After a reload, a back or forward traversal can run before the runtime is ready and has no durable scroll snapshot for the target history entry.

The violated invariant is that the Pages Router owns browser scroll restoration whenever the Next.js scroll restoration flag is enabled, with one stable history key per entry and routeChangeComplete emitted after the new page commits.

Resolve the Next.js config flag into process.env.__NEXT_SCROLL_RESTORATION, install the Pages Router runtime during next/router evaluation, persist Next-style sessionStorage scroll snapshots per history key, and render navigations through a stable commit boundary before emitting routeChangeComplete.

Regression coverage ports Next.js reload-scroll-backforward-restoration and verifies manual restoration plus exact scroll positions across reload, back, and forward traversal.

* fix(pages-router): sequence routeChangeComplete after scroll restoration and settle on render failures

* fix(router): guard against missing window.history in stampInitialHistoryState

* fix(router): defer hash scroll until after routeChangeComplete

Move hash scrolling out of renderPagesRouterElement's commit callback
and into the post-routeChangeComplete path, matching Next.js ordering:
x/y restoration happens during render commit, hash scrolling happens
after the completion event.

Also fix E2E test expectRouteChangeComplete to use one-shot event
listeners instead of checking for stale text, and add listener cleanup
to the fixture to prevent accumulation.

* fix(test): remove post-push deadlock and throw on missing events in E2E helper

expectRouteChangeComplete() now throws if window.next.router.events is
absent instead of silently resolving. Remove the redundant
expectRouteChangeComplete call after pushWithPagesRouter in the third
test — the awaited router.push already resolves after routeChangeComplete,
so registering a listener after it would deadlock.

* fix(test): replace as any casts with type-safe window.next narrowing in E2E scroll tests

* fix(router): narrow renderPagesRouterElement scroll param, drop dead hash branch

* fix(router): reset x/y scroll on hash routes before routeChangeComplete and cancel pending render on supersede

- Pass {x:0, y:0} through commit boundary for all scrollable
  navigations, not just hash-less ones (hash scroll deferred to after
  routeChangeComplete as before).
- Cancel pending render-commit Promise when a newer navigation starts,
  preventing hang when the first root.render() commit is dropped by
  React re-reconciliation.
- Add regression tests for both edge cases.

* fix(router): use SSR-safe layout effect in commit boundary and pin shallow scroll ordering

Address bonk review on #1905:
- swap the commit boundary's raw useLayoutEffect for the SSR-safe
  useNonWarningLayoutEffect pattern from shims/image.tsx so Pages Router
  SSR renders no longer log React's useLayoutEffect warning
- document that the default-noop commit boundary intentionally also wraps
  SSR and initial hydration
- document the intentional shallow-scroll-before-routeChangeComplete
  ordering and add a unit test pinning it

* fix(router): keep history-state scroll restore on popstate when scrollRestoration flag is off

Without experimental.scrollRestoration, popstate must still honour the
__vinext_scrollX/Y saved into history state on push, since a soft popstate
re-renders content the browser's native restoration can't position. Also
document why the popstate-time sessionStorage snapshot depends on
history.scrollRestoration = "manual".

* fix(router): guard render-commit canceller against late commits from superseded trees

* fix(router): defer current-history-key commit until beforePopState allows navigation

When beforePopState cancels a popstate the app stays on the previous
history entry, but _currentHistoryKey had already been updated to the
target key, skewing subsequent scroll-position bookkeeping. Move the
key commit below the beforePopState early-return, matching the
deliberate deferral of _lastPathnameAndSearch.

* chore(router): note intentional eager scroll snapshot; fix fixture link increment

- Document that the outgoing-entry scroll snapshot is deliberately written
  before the beforePopState gate: on cancellation the app stays on
  currentKey, so the saved value remains that entry's live scroll.
- Coerce id to a number in the pages-scroll-restoration fixture Link so
  the href increments numerically instead of string-concatenating.

* fix(router): keep manual scroll restoration opt-in Pages-Router-only

Gate installManualScrollRestoration on the document not being an App
Router one (window.next.appDir === true): with the now-global
__NEXT_SCROLL_RESTORATION define, an App Router app that value-imports
next/router for compat would otherwise have its native browser scroll
restoration disabled at module eval. Upstream only flips
history.scrollRestoration inside the Pages Router constructor, which
never runs on App Router documents.

Also document the hash-only popstate path discarding the per-entry
__next_scroll_<key> snapshot as intentional upstream parity (change()'s
onlyAHashChange branch passes null to this.set and only scrollToHash
runs), and add unit coverage for both behaviors.

* ci: run pages-scroll-restoration E2E project in the CI matrix

Add the missing E2E matrix entry so the ported Next.js regression spec
(reload-scroll-backforward-restoration.spec.ts) actually executes in CI,
matching the shape of the sibling single-shard Pages Router entries.

Also document why the soft-popstate scroll fallback differs between
manual restoration on ({ x: 0, y: 0 }) and off (null -> native auto
restoration handles unstamped entries), per review.

* refactor(router): fold App Router gate into manualScrollRestoration constant

The popstate handler's sessionStorage save/read branches gated on the
module-level constant, which lacked the window.next?.appDir check that
installManualScrollRestoration used, leaving those branches relying
solely on the __N state filter to stay inert on App Router documents.
Fold the appDir check into the constant so every consumer is
Pages-Router-only by the same gate; the App Router bootstrap stamps
window.next.appDir before any client module evaluates, so the
module-eval-time check is reliable.

* test(pages-scroll-restoration): default getServerSideProps id to string "0"

Route params always arrive as strings, so the numeric 0 fallback was
inconsistent with the string values the component relies on
(Number(id) + 1 href, id === "error" check). Default to "0" for type
consistency.

* test(pages-scroll-restoration): align fixture deps and vinext import with pages-basic

Import vinext via the workspace package name instead of reaching into
dist by relative path, and declare the same react/react-dom/vinext
dependencies as the other fixtures so the fixture is self-describing
and the pnpm-lock.yaml importer entry is populated.

* fix(router): snapshot outgoing scroll on hash-only pushes

Upstream Next.js snapshots the outgoing entry's scroll into
__next_scroll_<key> inside Router.push() itself, before change()'s
onlyAHashChange short-circuit, so hash-only pushes still capture the
departed entry's position. Our hash-only push branch returned before
saveScrollPosition() ran, so a later back-popstate to that entry
restored {x: 0, y: 0} instead of the position the user had reached.

Save the outgoing scroll before updateHistory mints the new key,
matching the full-navigation push path and upstream ordering.

* docs(router): clarify manual scroll-target fallback chain precedence

* test(shims): tag scrollRestoration App Router test as eval-order guard

* docs(router): note missing-snapshot fallback intent at forcedScroll default

---------

Co-authored-by: James <james@eli.cx>
2026-06-12 11:31:33 +01:00
github-actions[bot] 91c169a8fc chore: version packages (#1875)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@vinext/cloudflare@0.1.1 vinext@0.1.2
2026-06-12 10:30:11 +00:00
Nathan Nguyen fd1023321b fix(router): support experimental gesture push (#1909)
* fix(router): support experimental gesture push

Vinext did not expose useRouter().experimental_gesturePush when Next.js apps enabled experimental.gestureTransition. Upstream gesture-transition fixtures call the method inside a held async transition, so the target route never became visible before the canonical router.push completed.

The fix resolves the config flag into the same __NEXT_GESTURE_TRANSITION define used by Next.js, exposes the optional router method only under that flag, and lets gesture navigation use the existing RSC navigation pipeline with an immediate approved visible commit. The ported e2e fixture preserves the upstream held-transition flow and target/static/dynamic assertions.

* test(router): update navigate mock assertions to expect default transition commit mode

* fix(router): address ask-bonk review comments on gesture push

- track scheduled app router navigation in experimental_gesturePush for
  parity with push/replace, so a refresh() issued in the same task skips
  its redundant re-fetch
- document the synchronous visible-commit mode's null pendingRouterState
  invariant in the browser navigation controller
- add a unit test asserting experimental_gesturePush is only attached
  when the __NEXT_GESTURE_TRANSITION define is set

* style(tests): fix formatting in shims.test.ts

* docs(router): clarify gesture push normalization and flushSync commit paths

* test(router): fix unbound-method lint in shims test and document gesture spec coverage

* docs(router): clarify gesture define boolean form and spec held-state rationale

* docs(test): note gestureTransition is fixture-wide for the gesture spec only

* fix(router): no-op experimental_gesturePush before the navigation runtime is ready

Upstream gesturePush early-returns when getCurrentAppRouterState() is null,
so a gesture dispatched before hydration is a no-op. Previously vinext fell
through navigateClientSide's non-runtime branch and performed a real history
push. Guard on the runtime's navigate function (the same readiness check
navigateClientSide uses) and document that the un-awaited
void navigateClientSide(...) deliberately matches push/replace's
fire-and-forget rejection shape.

* docs(router): note gesturePush guard/dispatch runtime reads have no TOCTOU window

* docs(test): document gesture fixture's double-navigation divergence from upstream

---------

Co-authored-by: James <james@eli.cx>
2026-06-12 03:14:24 +01:00
Divanshu Chauhan 2da6991234 perf(server): eliminate redundant per-request parsing in the request pipeline (#1929)
* perf(server): make requestContextFromRequest cookies/query lazy

Cookies and query are consumed only by has/missing condition evaluation,
which most apps never configure. Defer parseCookies and searchParams to
lazy memoized getters so they run at most once and only when read.
Tighten RequestContext fields to readonly to lock in the read-only
contract. Mirrors the existing headersContextFromRequest pattern.

Refs #1911

* perf(server): hoist pathname split out of metadata route loop

handleMetadataRouteRequest iterates every registered metadata route and
matchMetadataRoute re-split the invariant cleanPathname for each dynamic
route, allocating O(routes) arrays per request. Compute the split once via
a memoizing closure; apps with no dynamic metadata routes never split.

Refs #1911

* perf(server): hoist constant header sets in prod-server

omitHeadersCaseInsensitive rebuilt a lowercased Set from a constant literal
array on every static-file response. Hoist the two constant sets to module
scope as ReadonlySet<string> and take them precomputed, dropping the
per-response map and allocation.

Refs #1911
2026-06-12 00:52:04 +01:00
James Anderson d3bbc4d558 test(e2e): close page before temp prod server in remaining specs (#1928)
Same latent race fixed for inline-css.browser.spec.ts in #1927: the
temp production server was closed during teardown while the page was
still open, so idle-scheduled requests (e.g. Link prefetches via
requestIdleCallback) could hit the closed port and log
ERR_CONNECTION_REFUSED — which the consoleErrors fixture turns into a
flaky failure. Close the page first in hash-rsc-requests and
client-reference-runtime-map too.
2026-06-11 23:31:23 +00:00
Nathan Nguyen 2737a38d46 fix(pages-router): support stream proxying in API routes (#1902)
* fix(pages-router): support stream proxying in API routes

* fix(pages-router): address review feedback on stream proxying PR

- Narrow auto-end condition to only skip ending when handler returns res
  (the destination of req.pipe(...).pipe(res)), preventing hangs from
  non-stream return values.
- Replace full-body buffering with a PassThrough-backed PagesResponseStream
  that resolves on first write, enabling real streaming responses.
- Add error handling to reject responsePromise when the response stream
  errors, preventing silent request hangs.
- Add regression tests: non-stream return auto-end, multi-chunk write,
  and response stream error handling.

* fix(pages-router): avoid hanging responses and PassThrough unhandled errors

- Narrow auto-end condition to  to prevent non-stream
  return values from hanging requests.
- Replace PassThrough + Readable.toWeb() with a direct ReadableStream controller
  in PagesResponseStream to eliminate Controller is already closed unhandled
  errors during stream proxying.
- Add destroy() override to error/close the stream body when the Node Writable
  is destroyed after streaming starts.
- Add rejectResponse callback to PagesResponseStream constructor for proper
  error propagation.
- Add regression tests for auto-end, multi-chunk streaming, and destroy error
  handling.

* fix(pages-router): destroy Node side when Fetch body is cancelled

- Reject writes in _write() when streamEnded or destroyed to prevent
  buffering chunks after cancellation.
- In the ReadableStream cancel handler, clear bufferedChunks and destroy
  the Node-compatible PagesResponseStream so upstream writers receive
  an error instead of silently accumulating data.
- Add regression test proving writes after body cancellation fail with
  an error and do not accumulate in the bridge.
- Rename multi-chunk test to be more accurate about what it verifies.

* fix(pages-router): settle response when res.destroy() is called without error

- In destroy(), if the response has not been resolved yet, resolve the
  response promise (with a closed stream) when no error is provided, or
  reject it when an error is provided. This prevents the request from
  hanging forever when a handler calls res.destroy() before any body
  write and returns the res object.
- Add regression test proving res.destroy() without error resolves to an
  empty 200 response instead of hanging.

* chore: trigger CI run for flaky E2E test validation

* fix(pages-router): track pipe event and fix request body cancellation

- Add `res.once("pipe", ...)` listener to detect when a handler pipes into the response without returning the writable. Skipping auto-end by return-value only missed the real-world pattern:

    (req, res) => { req.pipe(upstream).pipe(res); } // returns undefined

  Next.js uses the pipe event signal, not the handler return value.

- Fix request body cancellation: the async generator finally block now calls `reader.cancel()` before `releaseLock()`, restoring the pre-PR behavior where early return from `for await (chunk of req)` cancelled the underlying stream instead of just releasing the lock.

- Add regression tests for both pipe-without-return and pipe-with-return.

* fix(pages-router): drop handlerResult === res auto-end signal, rely on pipe event only

The `handlerResult === res` check was too broad — chainable helpers like
`return res.status(202)` return `this` without implying streaming, and would
cause a hang by skipping auto-end. Now that `res.once("pipe", ...)` provides
the real stream signal, the return-value check is redundant and harmful.

Removes:
- handlerResult variable and === res comparison
- comment about returning the writable

Adds:
- regression test for `return res.status(202)` not hanging

* fix(pages-router): address stream response review

* fix(pages-router): close IncomingMessage parity gaps in API route streams

- Yield Buffer chunks (zero-copy views) from the request readable and opt
  out of objectMode so req matches IncomingMessage byte-stream semantics:
  per-chunk chunk.toString("utf8") decodes instead of comma-joining byte
  values, and setEncoding()/read(n) behave byte-wise.
- Honour config.api.externalResolver: Next.js never auto-ends a response,
  and externalResolver: true is the documented contract for handlers that
  respond after the handler promise settles (e.g. proxy middleware that
  attaches its pipe asynchronously). Skip the auto-end safety net for such
  routes so they are not truncated to an empty response.

---------

Co-authored-by: James <james@eli.cx>
2026-06-11 23:29:58 +00:00
James Anderson 56393aedad test(e2e): close page before prod server in inline-css fixture teardown (#1927)
The inlineCssApp fixture closed its temp production server while the
page was still open. Link prefetches are scheduled via
requestIdleCallback and could fire after the test body finished,
hitting the closed port and logging ERR_CONNECTION_REFUSED, which the
consoleErrors fixture then turned into a flaky failure at teardown.

Close the page first so no late request can target the dead port.
2026-06-11 23:26:21 +00:00
Nathan Nguyen dea4472c2f fix(app-router): include parallel slot params in useParams (#1904)
* fix(app-router): include parallel slot params in useParams

App Router navigation state previously used only the primary route match params when setting request navigation context, RSC param headers, render observations, and optimistic navigation payloads. That lost catch-all params from active parallel slot branches, so useParams() diverged from the slot page's params prop after SSR and client navigations.

Next.js derives params from the selected router tree across parallel route branches. Resolve active slot params from route metadata, merge them into the navigation params boundary, and feed that selected param set through server render and optimistic navigation payloads.

Port the upstream parallel-route-navigations fixture and cover the route graph, selected params helper, and optimistic payload boundary.

* fix(app-router): preserve canonical pathname in navigation context after middleware rewrite

* fix(app-router): resolve parallel slot params for static, revalidation, and action paths

* chore: retrigger CI

* fix(app-router): address ask-bonk review comments on parallel slot params

- Remove unused  parameter from
- Add clarifying comment on routeParams fallback being deliberate no-op
- Use  (full matched params) instead
  of narrowed  as base for slot param merge,
  preserving interception-specific extras on ISR regeneration path

* fix(app-router): use full navigationParams in server-action re-render path

The server-action re-render path was passing narrowed
actionRerenderTarget.params to resolveAppPageNavigationParams,
dropping interception-specific extras from source-route intercepts.
Use actionRerenderTarget.navigationParams (full matched params) instead,
matching the pattern used in the dispatch ISR path at
app-page-dispatch.ts:602.

Adds unit tests for the intercepted-slot and mixed intercepted +
non-intercepted slot branches of resolveAppPageNavigationParams.

* docs(router): clarify decode invariant and type cast rationale in parallel-slot params

- app-optimistic-routing.ts: add comment explaining the pre-existing
  double-decode asymmetry between route params and slot params, noting
  TODO to converge decode passes
- app-server-action-execution.ts: expand the comment on the interceptOpts
  cast to document why it's safe and what a follow-up would look like

* fix(app-router): merge slot params for fresh intercepts

---------

Co-authored-by: James <james@eli.cx>
2026-06-11 23:54:27 +01:00
Nathan Nguyen 757610d2c6 refactor(router): plan same-page search and early navigation intent (#1900)
* feat(router): classify early navigation intent in planner

App Router same-page search and hash-only navigation decisions live inline in two separate executors: the shim derives hash-only changes from window.location, and the browser request loop derives same-page search changes from the committed snapshot. Each uses a slightly different predicate, so the early-intent classification cannot be tested without window, and the two paths can drift.

Add navigationPlanner.classifyEarlyNavigationIntent, a pure pre-fetch classifier that takes URL-delta facts and returns a typed decision: same-document scroll for hash-only changes, a cache-bypassing flight for same-path search changes, or an ordinary flight otherwise. This mirrors the classifyRscFetchResult surface added for fetch-result classification.

The classifier compares normalized search params so encoding or ordering differences that parse to the same query do not split a hash-only change into a search navigation. Unparseable hrefs fall back to an ordinary flight rather than masking a real failure as a same-page outcome.

Add the NC_SAME_DOC_SCROLL, NC_SAME_PAGE_SEARCH, and NC_CROSS_DOC_FLIGHT trace codes and a focused unit matrix. No runtime behavior changes yet; the executors cut over in a following commit.

* refactor(router): execute planned early navigation intent

The App Router shim and browser request loop still own the early navigation intent decisions. navigateClientSide derives hash-only changes inline via isHashOnlyChange, and the request loop derives same-page search changes inline via isSamePageSearchNavigation. That keeps the executors coupled to classification logic that now belongs in the planner, and the two predicates compared search params differently (raw vs normalized).

Replace both inline branches with navigationPlanner.classifyEarlyNavigationIntent. The shim acts on the sameDocumentScroll decision (history update plus hash scroll, no RSC fetch); the request loop consumes only the flightNavigation cache-bypass bit. Each executor still classifies against its own authoritative current reference (the shim against the live document, the loop against the committed snapshot), so redirect-hop and committed-state semantics are preserved while the decision logic lives in one tested place.

Delete isHashOnlyChange and isSamePageSearchNavigation along with their now-unused imports. The removed isHashOnlyChange startsWith("#") fast path was dead for the resolved fullHref argument, which toBrowserNavigationHref always prefixes with a path, so behavior is unchanged. The Pages Router keeps its own isHashOnlyChange in router.ts.

* fix(router): require same origin for same-document navigation intent

classifyEarlyNavigationIntent compared only the base-stripped pathname, the serialised search params, and the presence of a hash. It did not compare origin, so a cross-origin target whose path and search happened to match the current document was classified as a same-document scroll (for a hash target) or a cache-bypassing same-page search. navigateClientSide papers over this by filtering external URLs before the planner runs, but the planner is meant to be the semantic authority and should not carry an unstated same-origin precondition, especially as the navigate runtime is an ambient surface.

Gate both same-document outcomes on current.origin === next.origin so a different host falls through to an ordinary flight navigation. Add cross-origin same-path-plus-hash and same-path-plus-search cases to the unit matrix.

Also correct the search-comparison comment: URLSearchParams.toString() normalises encoding but not key order, and we intentionally do not sort, since query order can be observable.

* test(router): pin encoding-equivalent search params to same-page outcome

* refactor(router): consolidate duplicate snapshot-to-path helpers

* test(router): document early intent search normalization

* refactor(router): mark planner inputs as inert

---------

Co-authored-by: James <james@eli.cx>
2026-06-11 22:24:45 +00:00
Nathan Nguyen f5bee1a26f fix(app-router): preserve unstable_catchError boundaries (#1906)
* fix(app-router): preserve unstable_catchError boundaries

* test(e2e): add Next-parity test for shouldRerenderAppPageWithGlobalError (#1906)

Add a test proving that for uncaught post-shell RSC errors (with no
client boundary), the server preserves the original HTML stream and the
client renders global-error. This is the Next.js behavior that justifies
keeping shouldRerenderAppPageWithGlobalError unconditional at false.

The server cannot detect userland client boundaries like
unstable_catchError from the route manifest, so the only safe way to
get a global-error rerender is to make a targeted error-boundary test.

The test uses a loading.tsx boundary so the error is truly post-shell,
not caught by the pre-shell error-recovery catch block.

* fix(error): restore sentinel wrapper for falsy thrown values in unstable_catchError

Restores the _CatchErrorState sentinel wrapper ({ thrownValue: unknown }) so
falsy thrown values (null, undefined, 0, "") are routed to the fallback
instead of being treated as no error. Also restores ErrorInfo.error as unknown.

Adds back unit tests for falsy values, class-component lifecycle, and
unstable_retry behavior parity with the component-rendered fallback shape.

Refs: #1906

* fix(error): align ambient ErrorInfo.error type with runtime implementation

* refactor(app-router): remove shouldRerenderAppPageWithGlobalError dead code

The function always returned false and its _options parameter and
ShouldRerenderAppPageWithGlobalErrorOptions type were vestigial.
The call site at app-page-render.ts:892-904 was therefore never taken.

Remove the function, type, import, call site, and the now-redundant
unit test, leaving the shell-level recovery path in
renderAppPageHtmlStreamWithRecovery as the sole error recovery seam.

Addresses ask-bonk review comment on #1906.

* fix(test): restore typed globalAny view and document Fallback as any intent

Addresses two non-blocking review findings from ask-bonk on PR #1906:

- Restored the typed `globalThis as unknown as { window?: unknown }`
  pattern for window stubs in the unstable_catchError test section,
  replacing the `(globalThis as any).window` pattern that was a type-safety
  regression from the prior rewrite.
- Added an inline comment explaining why `Fallback as any` is necessary
  in the class-component lifecycle test: the test probes the inner
  _CatchError class directly, where the fallback function is used as a
  React component type (receiving a single `{ props, errorInfo }` object)
  rather than the public API signature `(props, errorInfo)`.

* chore: trigger CI

* fix(test): rename forwardedProps to props in unstable-catchError test

Addresses ask-bonk review finding on PR #1906: the test was seeding
the inner _CatchError class with the stale key name forwardedProps,
but the production wrapper now passes props (and isPagesRouter).
Since this test only exercises the App Router unstable_retry path
(which reads neither key), behavior was unaffected, but renaming
aligns the test with the current boundary shape for future readers.

* refactor(server): remove dead routeHasLocalBoundary field

Removing shouldRerenderAppPageWithGlobalError (commit abb416b)
deleted its only reader of routeHasLocalBoundary. The field is still
declared in the options type and populated on every render, but
nothing consumes it anymore. Removes:

- routeHasLocalBoundary from AppPageRenderOptions type
- The computation in app-page-dispatch.ts
- Two test stubs in app-page-render.test.ts

Addresses ask-bonk review finding on PR #1906.
2026-06-11 23:21:52 +01:00
Jerry Zhao 6d9d16da1e test(next-config): make CJS config fixture deterministic on Windows (#1922) 2026-06-11 23:02:30 +01:00
Jerry Zhao 0394b98633 test(og): pass POSIX-style ids to the og-font-patch transform fixture (#1925) 2026-06-11 23:00:00 +01:00
Jerry Zhao 9013bf8ca3 refactor(dev-lockfile): normalize stale lock file path in error message (#1926) 2026-06-11 22:59:49 +01:00
Jim Geurts 23dd15f763 fix(prod-server): stop double-evaluating the server bundle when chunks import the entry back (#1924)
* fix(prod-server): stop double-evaluating the server bundle when chunks import the entry back

The production server imported the built server entry with a ?t=<mtime>
query string. Node keys its ESM cache on the full URL including the query,
so any code-split chunk that resolves the same entry file by its plain URL
evaluated the entire server bundle a second time. Default Vite builds on
both supported majors (Rollup on Vite 7, Rolldown on Vite 8) hoist modules
shared between the entry's static graph and lazy route chunks into the
entry chunk, and the chunks import them back as ../../index.js; realpath-
canonicalized chunk ids also reach the entry via its real path when the
server was started through a symlinked path. Module-level singletons then
diverged between the two copies: boot-time initialization ran on the
instance the server imported while route handlers read the never-
initialized duplicate.

Import the entry by its bare canonical (realpathed) file:// URL on first
use so all importers converge on one module instance, and only append the
?t= cache-buster when the same path is imported again with a different
mtime — the same-process rebuild scenario the query existed for.

* docs(prod-server): clarify rebuild-branch tradeoff and probe constraints (#1924)

- note in resolveServerEntryImportUrl's JSDoc that the ?t= rebuild branch
  trades back the single-instance guarantee (bare chunk back-imports keep
  resolving to the first build); freshness + single instance only hold
  together on the first import of a path
- clarify the realpath try/catch only covers realpathSync.native failures,
  not missing entry paths (those still throw at statSync, as before)
- document that the prod-singleton-state fixture probe is only valid on a
  freshly built output path
2026-06-11 22:59:32 +01:00
Divanshu Chauhan 9f9c9249b9 perf(server): hoist per-request regex compilation out of SSR streaming and shim hot paths (#1915)
* perf(server): hoist close-tag regexes out of SSR stream boundary scanner

Replace per-iteration new RegExp(`</\s*>`, "i") in
findTrailingOpenHtmlRewriteExcludedRegionStart with a module-level frozen
lookup CLOSE_TAG_RES keyed by the four tag names constrained by
HTML_REWRITE_EXCLUDED_REGION_START_RE.

Call frequency: runs on every streaming App Router SSR response flush,
iterating once per <script>/<style>/<textarea>/<title> open tag in the
chunk. A page with N Suspense boundaries compiles O(N) regexes per chunk
without this fix.

Safety: regexes carry i-flag only (no g/y), so shared instances have no
lastIndex state and are safe across concurrent requests.

Closes #1910 (task 1/3)

* perf(server): hoist path-delimiter regexes in escapePathDelimiters

Replace per-call new RegExp(...) in escapePathDelimiters with two
module-level constants PATH_DELIMITERS_RE and PATH_DELIMITERS_ENCODED_RE.

Call frequency: decodePathParams calls escapePathDelimiters once per path
segment of every App→Pages bridge request, so an N-segment path previously
compiled N regexes per request.

Safety: g-flagged regexes are only used via String.prototype.replace, which
always resets lastIndex — no exec/test loop touches these instances.

Aligns with the hoisted PATH_DELIMITER_REGEX form already used in
routing/utils.ts:90 (the other port of the same Next.js utility).

Closes #1910 (task 2/3)

* perf(shims): replace per-render regex construction with constants and memoization

head.ts — escapeInlineContent: replace new RegExp(`<\/(tag)`, "gi") with a
two-entry module-level map INLINE_CLOSE_TAG_RES keyed by tag name. All call
sites guard with RAW_CONTENT_TAGS.has(tag) so tag is always "script" or
"style". Runs once per inline <script>/<style> element per SSR render.

image-config.ts — globToRegex: add module-level globRegexCache Map so each
distinct (separator, pattern) pair is compiled only once. matchRemotePattern
calls globToRegex twice per remotePatterns entry, and hasRemoteMatch iterates
all entries for every remote <Image>, so a page with M patterns and K images
previously compiled up to 2·M·K regexes per render from a fixed config.
Mirrors Next.js's own Map<string, RegExp> memoization in
packages/next/src/server/image-optimizer.ts.

Closes #1910 (task 3/3)
2026-06-11 13:13:04 +01:00
Nathan Nguyen b802f7e0b0 test(e2e): use Playwright fixture pattern for inline-css server lifecycle (#1914)
* fix(e2e): poll for server readiness before navigating in inline-css test

The inline-css browser test builds and serves a temporary fixture
outside Playwright's webServer config, so server readiness is not
guaranteed before page.goto() navigates. Under CI load, the browser
can connect before the server is accepting connections, causing
ERR_CONNECTION_REFUSED flakiness.

Added a waitForServer utility in tests/e2e/helpers.ts that polls the
server URL until it responds, then uses it in the inline-css test before
navigation. Uses 30s timeout with 300ms polling and 2s per-request
timeout, matching the pattern from packages/vinext/src/cloudflare/tpr.ts.

Fixes https://github.com/cloudflare/vinext/issues/1913

* fix(e2e): use Playwright fixture pattern for inline-css server lifecycle

Replace the waitForServer polling approach with Playwright's fixture
pattern (base.extend) to manage the inline-css test's server lifecycle.
This matches the pattern used in client-reference-runtime-map.browser.spec.ts.

The previous approach added a waitForServer utility to shared helpers.ts,
but startProdServer already waits for the server to listen via the
server.listen() callback, making the polling redundant. The fixture
pattern guarantees the server is ready before the test body runs and
handles cleanup in the finally block.
2026-06-11 13:11:52 +01:00
MaxtuneLee 88a9947e14 fix(trailing-slash): canonical url trailing slash support (#1888)
* fix: canonical url trailing slash support

* fix(metadata): prevent trailing slash on file-like and .well-known canonical URLs

* fix(metadata): remove trailing slash handling for .well-known URLs

* test: add tests for createAppPageRouteBodyMetadata function with body placement

* fix(metadata): match trailing slash URL scope

* fix(metadata): resolve URL object alternates

---------

Co-authored-by: James <james@eli.cx>
2026-06-11 13:10:41 +01:00
James Anderson 2e83e7f558 fix(edge-wasm): handle *.wasm?module imports in non-Cloudflare builds (#1877)
* fix(edge-wasm): handle \`*.wasm?module\` imports in non-Cloudflare builds (#1351)

In plain Node.js builds (deploy-suite / standalone `vinext start`),
Rolldown has no built-in handler for the `?module` query on `.wasm`
imports, so middleware and edge API routes that use:

  import wasm from './add.wasm?module'

would throw at bundle time.

Root cause: the `?module` query is a Cloudflare Workers / workerd
convention handled by `@cloudflare/vite-plugin`'s
`additionalModulesPlugin` (enforce:"pre"). When that plugin is absent
(e.g. after `vinext init` which emits a plain `vite.config.ts` with
only `vinext()`), no plugin resolves the query.

Fix: add a new `vinext:wasm-module-import` Vite plugin (enforce:"pre")
that, in the absence of @cloudflare/vite-plugin:

1. Intercepts `*.wasm?module` imports in `resolveId`.
2. Reads the WASM binary at load time and inlines it as base64.
3. Exports `await WebAssembly.compile(buffer)` via a virtual module —
   valid in Node.js (top-level await in ESM).

The `hasCloudflarePlugin` guard is checked inside the hook handler
(not as an array-spread condition) so it reflects the value set by
the `config` hook after plugin registration.

workerd forbids compiling WASM from bytes at runtime, so this path
intentionally never runs when @cloudflare/vite-plugin is present.

Fixes #1351.

* fix(wasm-module-import): suppress no-control-regex lint on virtual module regexes

Replace bare null-byte with unicode-escape in the two filter/replace regexes
and add oxlint-disable-next-line comments following the same convention used
in client-reference-dedup.ts. Fixes the Check job failure.

* fix(wasm-module-import): exclude @vercel/og from plugin scope, add resolveId tests

- Add importer guard in resolveId to skip imports originating from
  @vercel/og (resvg.wasm, yoga.wasm): vinext:og-font-patch converts
  those to dynamic imports with a .catch() disk-read fallback; if
  wasm-module-import intercepts them, the Node.js fallback never runs,
  the ~1.3 MB resvg WASM ships twice, and findEmittedWasmAsset dedup
  in vinext:og-assets breaks. Guard mirrors the pattern in the existing
  isVinextOgShimImporter() helper.
- Remove dead `return null` after `this.error()` (which throws); use
  `bytes!` non-null assertion to satisfy TypeScript.
- Add resolveId test suite: happy path, ?module query stripping, null
  resolver, og-collision guard (plain + virtual-prefix importer), and
  non-og pass-through.

Fixes ask-bonk findings on PR #1877.

* refactor(wasm-module-import): drop non-null assertion, document TLA and filter intent

* test(wasm-module-import): add build-level coverage, document runtime-gating assumption

* refactor(wasm-module-import): extract to plugins/, guard client environment, watch wasm file in dev

* fix(wasm-module-import): delegate target-owned modules

* refactor(wasm-module-import): share query stripping
2026-06-11 12:06:39 +00:00
Nathan Nguyen d2ffc83670 fix(config): define cache components flag as boolean (#1903)
* fix(config): define cache components flag as boolean

Disabled cache components currently compile to a truthy "false" string. That diverges from Next.js and makes bundled user code that checks !!process.env.__NEXT_CACHE_COMPONENTS select the cache-components path even when next.config rewrites select the legacy destination.

Mirror Next.js by defining process.env.__NEXT_CACHE_COMPONENTS as a boolean expression, and keep the local slot shim tolerant of both boolean defines and string env values. Add a faithful revalidatePath-with-rewrites production regression that proves rewritten static and dynamic routes invalidate after revalidating the resolved destination path.

* test(prod-server): cover cacheComponents enabled revalidatePath with rewrites

* test(prod-server): skip dist/ copy in cacheComponents fs.cpSync filter

Addresses review feedback: fs.cpSync(APP_FIXTURE_DIR, fixtureRoot)
copies the earlier-built dist/ directory into the temp fixture before it
is immediately deleted. Adding a filter skips the unnecessary copy.
2026-06-11 12:53:35 +01:00
James Anderson f5355964aa fix(pages-router): set x-nextjs-deployment-id on SSG _next/data responses (#1863)
* fix(pages-router): set x-nextjs-deployment-id on SSG _next/data responses

Pages Router `/_next/data/<buildId>/<page>.json` responses were missing the
`x-nextjs-deployment-id` response header that Next.js sets on these routes
when a deployment ID is configured. The client router reads this header to
detect when a new deployment has been rolled out and triggers a hard
navigation for deployment-skew protection.

Root cause: the `isDataReq` short-circuit path in `pages-page-handler.ts`
that builds the JSON envelope (`buildNextDataJsonResponse`) never injected
the header. Next.js's `pages-handler.ts` sets `NEXT_NAV_DEPLOYMENT_ID_HEADER`
on every `isNextDataRequest` response (success, redirect, and notFound cases).

Fix: read `process.env.__VINEXT_DEPLOYMENT_ID || process.env.NEXT_DEPLOYMENT_ID`
(the runtime-available deployment ID, inlined at build time by Vite's define
transform) and set `x-nextjs-deployment-id` on the `_next/data` response
headers when a deployment ID is configured.

Maps to test: `pages ssg data deployment skew - hard navigate when a new
deployment occurs > header with deployment id > header is set on data routes`.

Fixes #1829

* fix(pages-router): complete x-nextjs-deployment-id parity for _next/data (bonk #1829)

Address all three ask-bonk findings on PR #1863:

1. Incomplete parity — add x-nextjs-deployment-id to redirect and notFound _next/data
   exits in pages-page-data.ts (buildPagesRedirectResponse, buildPagesDataNotFoundResponse).
   Thread deploymentId through ResolvePagesPageDataOptions and pass it from
   pages-page-handler.ts, matching the success-path pattern already in that file.

2. Dev/prod parity — patch dev-server.ts to set x-nextjs-deployment-id on all three
   _next/data exits: the writeGsspRedirect isDataReq path, the getStaticPaths/
   getServerSideProps/getStaticProps notFound isDataReq paths, and the success
   JSON envelope short-circuit (isDataReq block). Mirrors the prod handler.

3. Add regression tests asserting x-nextjs-deployment-id is present on _next/data
   success / redirect / notFound responses in both pages-page-data.test.ts (unit,
   via deploymentId option) and pages-page-handler.test.ts (integration, via
   process.env.__VINEXT_DEPLOYMENT_ID), and absent when no env var is set.

* fix(pages-router): add x-nextjs-deployment-id to wrong-buildId/route-miss _next/data 404s (#1829)

Fixes the deployment-skew gap identified in review: `buildNextDataNotFoundResponse` now
includes the `x-nextjs-deployment-id` header so all three wrong-buildId/route-miss exits
(normalizePagesDataRequest, prod-server Node path, pages-page-handler route-miss) surface
the deployment ID to the client router. Adds unit tests for the new header on all relevant
exits.

* fix(pages-router): set deployment-id header on remaining two dev-mode _next/data 404 exits (#1829)

Patches the stale-buildId 404 in the vite-dev middleware (index.ts) and
the route-miss data 404 in createSSRHandler (dev-server.ts) to set
x-nextjs-deployment-id, matching prod parity via buildNextDataNotFoundResponse().

* test(pages-router): cover dev-mode _next/data deployment-id header exits

Drive the two dev-only exits flagged in review through the real fixture
dev server: the wrong-buildId data 404 in the plugin middleware
(index.ts) and createSSRHandler's route-miss data 404 (dev-server.ts),
plus the dev success path and the no-deployment-id case.

* fix(pages-router): skip deployment-id header on /_error and /500 data success responses

Next.js pages-handler.ts guards the success-path x-nextjs-deployment-id
injection with `!isErrorPage && !is500Page`. Mirror that exclusion in
both the prod success short-circuit (pages-page-handler.ts) and the dev
one (dev-server.ts), and lock it in with a prod unit test (/_error and
/500) plus a dev integration test (/500).
2026-06-11 00:39:16 +00:00
Nathan Nguyen 71e2e4762a refactor(router): plan RSC fetch result classification (#1889)
* fix(router): preserve streamed RSC redirect targets

Streamed RSC redirect headers currently duplicate redirect lifecycle handling in the browser loop. That path preserves the target hash, but it does not share the same helper boundary as response URL redirects and cannot be tested independently.

The browser loop needs a pure resolver that applies the same external-origin, depth, and same-target laws while treating the streamed header as the visible redirect target.

Add resolveStreamedRscRedirectLifecycleHop and focused helper coverage for external redirects, depth exhaustion, same-target detection, target hashes, hash-only changes, and visible query preservation.

* feat(router): add RSC fetch result trace codes

Fetch-result classification needs trace causes that can distinguish invalid RSC payloads, compatibility hard navigations, redirect follow or terminal outcomes, streamed redirect loops, and normal commit continuation.

The existing navigation trace schema only names decoded commit decisions, so pre-decode HTTP/RSC decisions would otherwise be opaque or forced through unrelated reason codes.

Add the reason codes and fetch-result fields without changing runtime behavior.

* feat(router): classify RSC fetch results in planner

RSC navigation currently classifies invalid payloads, compatibility mismatches, response redirects, and streamed redirects inline in the browser request loop. Those decisions are semantic planner decisions, but they are not independently testable while embedded in the executor.

Add a pre-decode RSC fetch-result classifier with typed hard-navigation causes, redirect-follow output, body-discard intent, and trace entries. The classifier preserves the existing precedence ladder and routes streamed redirects through the shared lifecycle law.

Add a focused unit matrix for invalid payloads, compatibility mismatch, response-URL redirects, streamed-header redirects, same-target loop guarding, target-hash preservation, cached precedence, and normal commit continuation.

* refactor(router): execute planned RSC fetch decisions

The browser navigation request loop currently owns semantic fetch-result decisions for invalid RSC responses, compatibility mismatches, response URL redirects, and streamed redirect headers. That keeps the hot executor coupled to decision logic that now belongs in the planner.

Replace those inline branches with navigationPlanner.classifyRscFetchResult calls for cached and live responses. The executor now performs only effects: diagnostics, body discard, hard navigation, redirect loop variable updates, and commit fallthrough.

This preserves existing history-mode fallback and response-URL behavior while applying the streamed same-target loop guard introduced by the planner classifier.

* chore(router): keep RSC fetch planner exports tight

The fetch-result planner cutover added helper-only types and left the redirect depth constant exported after the browser executor stopped importing it.

Those symbols are internal implementation details, and keeping them exported makes the new planner surface noisier than the runtime contract requires.

Make the helper-only aliases and redirect depth constant internal. Re-run focused tests, knip, full check, app-router E2E coverage, and the vinext build after the cleanup.

* chore: retrigger PR checks

* ci: make release checkout credentials explicit

The zizmor check flags the release workflow checkout because it relies on the default persisted checkout token. That token is intentionally needed by changesets/action to push the version branch, tags, and releases.

Set persist-credentials: true explicitly so the accepted release requirement is encoded in the workflow instead of depending on the checkout default.

* chore: retrigger preview publish

* refactor(router): reuse streamed redirect target

* refactor(router): share RSC redirect lifecycle ladder

* Apply suggestion from @james-elicx

---------

Co-authored-by: James Anderson <james@eli.cx>
2026-06-11 00:37:12 +00:00
James Anderson f6b07eebcc fix(pages-router): buffer SSR response for crawler/bot User-Agents (#1876)
* fix(pages-router): buffer SSR response for crawler/bot User-Agents

Pages Router edge-runtime SSR was streaming HTML to all clients, including
crawlers like Googlebot and Google-PageRenderer that cannot parse incrementally
flushed HTML. This caused the Next.js compat test
`streaming-ssr-edge/should not stream to crawlers or google pagerender bot`
to fail: bots received multi-chunk responses without an ETag.

Mirror Next.js's behaviour from `send-payload.ts`: detect crawler UAs via
`isPagesStreamingBot()` (matching Next.js's html-bots.ts + is-bot.ts regex
set), await the full compositeStream, generate a FNV-1a 52-bit ETag, and
return a single-chunk Response. Normal browser UAs continue to stream.

* fix(pages-router): add If-None-Match→304, ISR-HIT ETag, and UA-gating divergence comment

- Export `generatePagesETag` and add `etagMatches` helper (weak/strong ETag
  comparison mirroring Next.js `sendEtagResponse` / RFC 7232 §3.2).
- `renderPagesPageResponse`: accept `ifNoneMatch` option; return 304 when the
  buffered bot response's ETag matches, with an empty body.
- `resolvePagesPageData`: accept `userAgent` + `ifNoneMatch`; attach an ETag
  to ISR cache-HIT responses for bot UAs (consistent with fresh-MISS path);
  return 304 on HIT when If-None-Match matches.
- `pages-page-handler`: plumb `if-none-match` request header into both
  `resolvePagesPageData` and `renderPagesPageResponse`.
- Add a clear divergence comment in `renderPagesPageResponse` documenting
  that vinext gates buffering/ETag on the crawler UA rather than Next.js's
  `isDynamic`-based flag.
- Tests: 8 new cases covering 304/200 on match/mismatch, non-bot 304 bypass,
  weak-ETag comparison, ISR-HIT ETag attachment, and ISR-HIT 304.

* fix(pages-router): address ask-bonk review — STALE ETag/304, comment fixes, no-cache

- Hoist repeated bot ETag/304 logic into `applyBotETagAndCheck` helper so the
  same code covers both the ISR cache-HIT and cache-STALE branches; previously
  the STALE branch silently omitted ETag headers and 304 short-circuits for
  crawler UAs
- Add `requestCacheControl` option to `RenderPagesPageResponseOptions` and
  `ResolvePagesPageDataOptions`; skip the 304 short-circuit when the request
  carries `Cache-Control: no-cache` (matches `fresh` package behaviour used by
  Next.js's `sendEtagResponse`)
- Fix comment: ETag section header said "weak ETag by default" — Next.js
  `generateETag()` defaults to strong ETag (`weak=false`); update to match
- Fix comment: `etagMatches` said Next.js uses the `etag` npm package with
  `weak: true`; it actually uses the `fresh` package for staleness checking;
  replace with accurate description
- Add tests: STALE-branch ETag attach, STALE 304, STALE non-bot skips 304,
  and `no-cache` bypasses 304 on all three paths (fresh-MISS, HIT, STALE)

* docs(pages-router): correct RFC 7232 citation for weak ETag comparison (§3.2 → §2.3.2)

* docs(pages-router): note 304-on-dynamic consequence of UA-gated ETag divergence

* refactor(pages-router): share the no-cache bypass check between MISS and ISR bot paths

* refactor(pages-router): move fnv1a52 ETag hash into utils/hash.ts alongside fnv1a64
2026-06-11 00:30:13 +00:00
James Anderson ce29f9c6aa fix(scss): preprocess SCSS CSS-module composes deps via SassAwareFileSystemLoader (#1882)
* fix(scss): preprocess SCSS CSS-module composes deps via SassAwareFileSystemLoader

postcss-modules' built-in FileSystemLoader reads files referenced by
`composes: className from './other.module.scss'` as raw text — without
Sass preprocessing.  For .scss files this leaves SCSS variables and bare
@import directives in the CSS output, causing LightningCSS to crash with
"Invalid empty selector" during production builds.

Fix: introduce SassAwareFileSystemLoader that delegates to Vite's
`preprocessCSS` API for every `composes:` dependency, so Sass compilation
runs before CSS-module scoping.  Register it via `css.modules.Loader` in
vinext's Vite config hook and thread the resolved config through via a new
`setSassLoaderResolvedConfig` call in the `configResolved` hook.

Fixes the following deploy-suite tests (both sass and sass-embedded variants):
- test/e2e/app-dir/scss/nm-module/nm-module.test.ts
- test/e2e/app-dir/scss/nm-module-nested/nm-module-nested.test.ts
- test/e2e/app-dir/scss/composes-external/composes-external.test.ts

Part of #1825 (non-tilde CSS-module/composes cases; complements #1881)

* fix(scss): address review feedback on SassAwareFileSystemLoader

- Guard the css.modules.Loader injection: respect a user's explicit
  css.modules: false (mergeConfigRecursively would otherwise re-enable
  CSS Modules with an object override) and never clobber a
  user-provided custom Loader. The override is precomputed as a typed
  const so the conditional spread doesn't disturb the config literal's
  contextual typing.
- Surface composes preprocessing failures via config.logger.warn
  instead of a bare catch {}, so missing composed classes are
  observable; a missing/unreadable dependency file now rejects like
  postcss-modules' FileSystemLoader did.
- Use Vite's exported preprocessCSS + PreprocessCSSResult type via a
  top-level import instead of the lazy dynamic import and stringly
  typed casts.
- Preserve parity for composes from non-*.module.* files: hand
  preprocessCSS a virtual *.module.* filename so plain '.css' deps are
  still scoped and export tokens extracted, matching the built-in
  FileSystemLoader.
- Port the three failing Next.js fixtures (composes-external,
  nm-module, nm-module-nested) as production-build regression tests in
  tests/scss-composes.test.ts, plus a plain .module.css / non-module
  .css parity test. All three SCSS tests reproduce the original
  "[lightningcss minify] Invalid empty selector" crash when the
  Loader injection is disabled.
- Add sass as a root devDependency so the SCSS tests (including the
  previously always-skipped tests/scss.test.ts) actually run in CI;
  drop the now-redundant knip ignore entry. Installing sass makes
  Vite's SassPreprocessorOptions resolve to the concrete sass types
  (previously any), so the tilde-importer's importers array now
  carries an explicit SassPreprocessorOptions["importers"] cast.

* fix(scss): bind composes-loader config per plugin instance; scope extensionless deps

- Replace the module-level resolved-config singleton with a per-vinext-
  instance binding (createSassAwareFileSystemLoader), so multiple builds in
  one process never preprocess composes deps with another build's config.
- Cover extensionless composes deps in the virtual *.module.* rename
  (append .module.css) so their tokens are scoped instead of silently
  dropped; add a parity test case.
- Pin url() pass-through behaviour for composed deps in the parity test
  (verbatim, never mangled into placeholders — matches the built-in
  FileSystemLoader, verified against a vanilla Vite build).

* docs(scss): document the per-subtree recursion boundary of the composes loader

Notes the two structural consequences of delegating nested composes
recursion to preprocessCSS (per-subtree duplicate inlining collapsed by
LightningCSS, and no cross-boundary cycle short-circuit for invalid
circular composes), per review.

* fix(scss): fail the build on composed-dep preprocessing errors

Only a missing Sass implementation is downgraded to a logged warning;
any other preprocessCSS error (e.g. a Sass syntax error in the composed
dependency) now propagates and fails the build, matching postcss-modules'
built-in FileSystemLoader instead of shipping a green build with
silently-missing classes. Docstrings updated to accurately describe the
silent empty-token path when no resolved config is bound. Adds a
regression test for the fail-loudly path.

* chore(deps): move sass to the workspace catalog; drop the now-dead dynamic skip in scss.test.ts

Review feedback on #1882: sass belongs in the pnpm workspace catalog
rather than pinned inline in the root package.json. With sass now a
guaranteed root devDependency, the runtime describeIfSass skip in
tests/scss.test.ts is dead code — the suite always runs — so make the
unskip explicit by removing the conditional machinery.

* rebuild lockfile
2026-06-11 00:29:51 +00:00
Jerry Zhao 55815233c8 fix(routing): normalize route root to forward slashes, drop downstream path workarounds (#1896)
* routing: normalize the route root to forward slashes and drop downstream workarounds

* fix(routing): compare findOwnerRouteForDir paths in forward-slash space

With appDir now normalized to forward slashes, the ancestor walk's
current === appDir termination never fired on Windows (current descends
through native path.join/path.dirname and stays backslash), so the walk
overshot the app root and could attach a sibling intercept to the wrong
owner. Top-level markers had the inverse mismatch: a forward-slash dir
probed against backslash routesByDir keys.

Normalize dir, appDir, routesByDir keys, and route file paths to
forward slashes inside the lookup so all comparisons happen in one
separator space, and add POSIX-runnable unit tests simulating the
Windows path shapes.

* refactor(routing): use normalizePathSeparators in findOwnerRouteForDir

Swap the inline backslash replaces for the shared util. It is a
platform-gated no-op on POSIX, so the Windows-shape unit tests mock it
to keep exercising the normalization logic on POSIX CI.

---------

Co-authored-by: James <james@eli.cx>
2026-06-11 00:17:22 +00:00
James Anderson 835e6b9943 fix(app-router): suppress redirect console errors in production onCaughtError (root-layout-redirect) (#1878)
* fix(app-router): suppress redirect console errors in production onCaughtError (#1830)

When redirect() is called from a 'use client' root layout (or any client
component), React catches the NEXT_REDIRECT sentinel via RedirectErrorBoundary
and then calls the hydrateRoot onCaughtError callback. In dev mode vinext
already filtered these via devOnCaughtError, but the production path had no
onCaughtError at all — React's built-in fallback calls console.error, producing
a spurious browser console error that fails the Next.js compat test assertion
`expect(foundErrors).toBe(false)`.

Fix: add prodOnCaughtError to app-browser-error.ts that silently drops
navigation signal errors (NEXT_REDIRECT, NEXT_NOT_FOUND, NEXT_HTTP_ERROR_FALLBACK)
and logs all other caught errors, preserving React's default behavior.

Add fixture tests/fixtures/root-layout-redirect/ (dedicated 'use client' root
layout with redirect()) and Playwright project root-layout-redirect (port 4184)
with spec porting the Next.js root-layout-redirect > should work using browser.

Part of #1830

* fix: include result/ page in root-layout-redirect fixture

* fix: add lockfile entry for root-layout-redirect fixture, use prod server, import isNavigationSignalError

Three fixes to unblock catastrophically-failing CI:

1. pnpm-lock.yaml: Add missing importer entry for
   tests/fixtures/root-layout-redirect. The fixture was added without
   updating the lockfile, causing ERR_PNPM_OUTDATED_LOCKFILE on every
   CI job during `vp install`.

2. playwright.config.ts: Switch the root-layout-redirect server from
   `npx vp dev` (dev mode) to `vinext build + vinext start` (production
   mode). The fix under test — prodOnCaughtError — is only active in
   production builds; running in dev mode exercised the pre-existing
   devOnCaughtError path and never touched the new code.

3. app-browser-error.ts: Replace the inline isNavigationSignalDigest
   helper with an import of isNavigationSignalError from
   utils/navigation-signal.ts. The module is dependency-free and
   already in the production browser bundle; inlining it reintroduced
   the drift risk that navigation-signal.ts was created to prevent.

Addresses ask-bonk findings: blocking (test ran in dev mode) and
maintainability (inline classifier duplication).

* test: add prodOnCaughtError unit tests, run root-layout-redirect e2e in CI, scope gitignore negation
2026-06-11 01:03:03 +01:00
James Anderson 9194cb55c6 fix(pages-router): hard-navigate to App Router destinations from Pages Router links (#1879)
* fix(pages-router): hard-navigate to App Router destinations from Pages Router links

When a Pages Router <Link> targets an App Router route (detected via the
prefetch manifest and recorded as `components[path] = { __appRouter: true }`),
`performNavigation` now checks for that marker and immediately calls
`window.location.assign/replace` instead of attempting a Pages Router SPA
fetch cycle that cannot succeed.

Mirrors Next.js router.ts:1448-1453. Fixes the deploy-suite test
`pages-to-app-routing > should work using browser`.

- packages/vinext/src/shims/router.ts: add __appRouter hard-nav guard
- tests/fixtures/app-basic/app/about/page.tsx: add id="app-page" to <h1>
- tests/fixtures/app-basic/pages/pages-to-app/[slug].tsx: new GSSP fixture page
- tests/e2e/app-router/pages-to-app-routing.spec.ts: new Playwright regression test

* fix(pages-router): replace no-explicit-any cast with in-operator type narrowing

`(getPagesRouterComponentsMap()[_appPath] as any)?.__appRouter` triggered
the `no-explicit-any` lint rule. Replace with a two-step lookup that uses
the `in` operator so TypeScript narrows the union type
`{ __appRouter: true } | Record<string, unknown>` without an `any` cast.

* fix(pages-router): normalize trailing slash in __appRouter marker key, rename locals, pin fast-path test

- Strip trailing slash on both the write side (markAppRouteDetectedOnPrefetch)
  and the read side (performNavigation) so the marker key agrees when
  trailingSlash:true adds a slash to the prefetch URL but not to the nav URL
  (or vice-versa via router.prefetch with a raw un-normalised path).
  Mirrors Next.js: removeTrailingSlash(removeBasePath(pathname)) at router.ts:1442.
- Rename _appPath/_appPathEntry to appPath/appPathNorm/appPathEntry (they are
  used, not ignored; the underscore prefix was misleading).
- Add two new unit assertions in pages-router-app-prefetch-detection.test.ts:
  one pins that the marker key is always stored without trailing slash, and one
  pins that performNavigation calls window.location.assign (the fast-path) when
  the __appRouter marker is present, so a regression in the new code path cannot
  be silently masked by the pre-existing fallback.

* test(pages-router): address review nits in pages-to-app navigation tests

- e2e: wait for App Router hydration after the hard navigation so the
  test asserts the App Router landing explicitly instead of only
  matching the new DOM
- unit: drop the unnecessary microtask tick before asserting
  window.location.assign — the fast path has no await before it, so
  asserting synchronously also pins that the hard navigation cannot
  lose a race against the SPA path
2026-06-11 01:01:54 +01:00
Nathan Nguyen 08504a7745 fix(app-router): preload next/dynamic chunks with CSP nonce (#1594)
* fix(app-router): preload next/dynamic chunks with CSP nonce

Rendered next/dynamic boundaries produced no SSR preload links for their client chunks. That diverged from Next.js and broke nonce-based CSP tests that inspect preload tags before hydration.

The runtime assumed React.lazy alone was enough for dynamic imports. It never carried the dynamic module IDs from the source call into SSR, and client JS chunk URLs did not use Next.js's static/chunks path shape.

Add a focused dynamic metadata transform, resolve boundary files from the client build manifest, emit nonce-bearing preload hints during SSR, and keep client JS assets under _next/static/chunks. Ported regression coverage verifies the nonce and the emitted path shape.

* fix: honor assetPrefix for dynamic preload globals

* test: cover asset-prefixed dynamic preload nonces

App Router production only covered the default dynamic preload URL path. That left assetPrefix regressions at the manifest-to-runtime emission boundary unguarded.

Add a startProdServer regression that builds app-basic with assetPrefix "/cdn" and asserts nonce-bearing next/dynamic chunk preloads render under /cdn/_next/static/chunks/.

* test: isolate asset-prefixed prod server globals

The assetPrefix regression starts a second production server in the same Vitest process. startProdServer and the generated RSC runtime install global manifest and module-loader state, so leaving the temporary build's globals in place breaks later production requests in the shared server.

Snapshot and restore the relevant globals around the temporary /cdn server while keeping the integration assertion at the real runtime boundary.

* refactor: reuse shared record guard in dynamic preload metadata

The dynamic preload metadata transform carried a local object guard even though the codebase already has a shared record predicate. That made the AST helper drift from the existing non-array record invariant used elsewhere.

Reuse isUnknownRecord from utils/record and keep the plugin-specific AST alias local to the transform.

* fix: make dynamic preload metadata binding-aware

The next/dynamic metadata transform matched calls by imported identifier text. Shadowed parameters and block bindings with the same name were therefore mutated even when they no longer referred to the next/dynamic import.

Walk the parsed module with lexical binding state so shadowed names are excluded, and collect object-form imports only from loader/modules rather than every property on the options object.

* fix: model switch and class scopes in dynamic preload transform

The dynamic preload metadata transform still treated imported next/dynamic names as active inside switch case lexical scopes and named class expression bodies. That could inject loadableGenerated metadata into calls that resolve to local bindings rather than the import.

The scope walker now removes switch case-block bindings while traversing case tests and consequents, leaves the switch discriminant in the outer scope, and scopes named class declarations and expressions through their children. Regression tests cover switch case shadowing and named class expressions.

* fix: address PR review feedback for next/dynamic CSP nonce

- Drop `as="style"` from `<link rel="stylesheet">` — `as` is a
  preload attribute per the HTML spec, semantically incorrect on
  stylesheet links. Browsers ignore it but it produces bad HTML.
- Remove brittle `import(` string gate from the transform — it could
  miss `import ("./x")` (whitespace between import and paren). The
  Vite filter already gates on "next/dynamic" and the AST parse is the
  real validation.
- Add comment explaining MagicString mutation safety in Promise.all.
- Add comment explaining AST end-exclusive assumption on closeParen.
- Add test for whitespace-separated dynamic import syntax.

* fix: update global.d.ts comment to mention asset prefix, fix formatting

* refactor: extract computeClientRuntimeMetadata shared helper

Extract the duplicated client-manifest runtime metadata computation
(lazy chunks, dynamic preloads, client entry) into a single shared
helper in utils/client-runtime-metadata.ts.

Both prod-server.ts (Pages Router Node.js production server) and
index.ts (Cloudflare closeBundle hook) now call the same helper,
eliminating the highest-risk seam in the PR where basePath/
assetPrefix handling produced bugs.

* test: add TSX-generic and object-form metadata regression tests

- Add post-type-strip generic call test verifying multi-line
  dynamic() calls work after TS/JSX stripping by esbuild.
- Add object-form existing loadableGenerated preservation test
  to guard against duplicate injection in the object overload.

* chore: remove unused ClientRuntimeMetadata type export

* revert: discard unrelated lockfile change from previous commit

* test: replace deploy test simulators with computeClientRuntimeMetadata

simulateCloseBundleAppRouter and simulateCloseBundlePagesRouter
no longer hand-roll lazy chunk and dynamic preload computation.
They call the shared computeClientRuntimeMetadata helper directly,
matching production wiring.

Also:
- Update helper doc comment to mention Node server startup
- Remove unused imports (manifestFileWithAssetPrefix,
  manifestFileWithBase, computeDynamicImportPreloads,
  dynamicImportPreloadsWithBase) from deploy.test.ts

* test: add absolute assetPrefix CSP nonce tests and clean up redundant globals

* fix(app-router): keep CSP nonce on next/dynamic preloads from Server Component call sites

DynamicPreloadChunks rendered in the environment of the dynamic() call site. For a Server Component call site it ran in the RSC environment, where the script-nonce React context is unavailable, so the emitted dynamic preload <link>s dropped the request nonce — a CSP violation under `script-src 'nonce-…' 'strict-dynamic'`. The existing tests missed this because every fixture called dynamic() from "use client" modules, which render in the SSR pass where the nonce is present.

Extract DynamicPreloadChunks into its own "use client" module (mirroring Next.js's PreloadChunks and vinext's next/script shim) so it always renders in the SSR pass where withScriptNonce() installs the provider, regardless of whether dynamic() is called from a Server or Client Component.

Add fixture regression tests: server-call-site JS and CSS preloads carry the nonce, an ssr:false boundary emits no server preload (Next.js loadable.tsx parity), and preloads are still emitted without a nonce when no CSP is set.

* test(app-router): add browser CSP-nonce e2e for Server Component next/dynamic call site

The existing csp.spec.ts browser test only exercises the client call-site page (/nextjs-compat/dynamic). Add a Playwright test for the Server Component call site (/nextjs-compat/dynamic/rsc-imports-client) asserting the lazily-loaded client widget hydrates under script-src 'nonce-…' 'strict-dynamic' with no CSP violations in the console.

* fix(app-router): correct next/dynamic preload key-spaces and harden the transform

Addresses review findings on the next/dynamic CSP-nonce feature.

- Lazy chunks must stay in the SSR-manifest key-space (basePath only); only dynamic preloads take the assetPrefix. Applying an absolute-URL assetPrefix to lazy chunks broke the Pages Router modulepreload-exclusion membership test and leaked lazy chunks into <link rel=modulepreload>.

- Resolve symlinks on both sides when computing a dynamic boundary's module ID (reusing relativeWithinRoot/tryRealpathSync), so the key matches the client manifest under pnpm/Cloudflare symlinked layouts instead of silently dropping the preload.

- Throw on dynamic() calls with >2 args (Next.js react-loadable parity).

- Insert the generated options arg right after the first arg, preserving comments/whitespace (the previous substring-comma scan ate commas inside comments).

- Recurse into _next/static/chunks/ in the on-disk client-entry fallback (client JS now lands under chunks/).

- Add typeof-window guard to DynamicPreloadChunks and document the deliberate as="style" omission for stylesheet links.

- Extract buildRuntimeGlobalsScript so the Cloudflare closeBundle injection shares one source of truth with the deploy tests (which now mirror includeClientEntry + the mixed app+pages branch).

Tests: lazy/dynamic key-space split incl. absolute-assetPrefix leak regression and a realistic already-prefixed manifest; mixed app+pages client-entry injection; symlinked module-id resolution; nested dynamic() calls; >2-arg throw; comment-safe insertion; ssr:false positive content assertion; honest dev-mode E2E naming (preload-nonce coverage lives in the prod-server Vitest suite).

* fix(app-router): fix parenthesized next/dynamic loader corruption + harden re-review findings

Follow-up to the re-review of 1709db35.

- Fix a regression where inserting the options arg at the first argument's AST end corrupted a parenthesized loader (dynamic((() => import('./x')))) into a sequence expression that DROPPED the loader. Insert at the call's closing paren (paren-safe) with a comment-aware trailing-comma check (keeps comment-safety, avoids ',,'). Verified all four arg shapes via the real transform.

- Add an end-to-end round-trip test: real computeClientRuntimeMetadata -> globalThis.__VINEXT_LAZY_CHUNKS__ -> real collectAssetTags, asserting a lazy chunk is excluded from modulepreload under basePath+assetPrefix (consumer-side guard for the lazy-chunk key-space fix).

- Replace the hand-rolled simulateAssetTagFiltering with the real exported collectAssetTags (kills drift + a stale 'in index.ts/can't import' comment).

- Add an on-disk client-entry fallback test for the real _next/static/chunks/ layout (prior tests only used the flat layout).

- Hardening: memoize root realpath in toManifestModuleId; .length/keys guards in buildRuntimeGlobalsScript; DEBUG-gated parse-failure log; line:col in the >2-arg error; document the preserveSymlinks:false dependency; negative test for a shadowed dynamic(a,b,c) not throwing; ssr:false asserts visible text; honest typeof-window guard + E2E comments.

* test(app-router): fix stale comments + harden next/dynamic tests (3rd review pass)

Addresses the 3rd re-review of the next/dynamic CSP-nonce work. No runtime behavior change (doc + test hardening + one behavior-neutral nonce-prop cleanup).

- Fix two stale comments claiming DynamicPreloadChunks is NOT 'use client' (the opposite of the implemented, correct behavior) in the prod-server test and the rsc-imports-client fixture — leftovers from when the bug was first reproduced.

- ssr:false / assetPrefix tests: match the fetchPriority attribute case-INSENSITIVELY so a future React lowercasing can't make the ssr:false negative assertion pass vacuously.

- Add bare-promise dynamic(import(...)) transform tests (+ parenthesized variant) via a shared firstDynamicCallArgTypes AST helper; strengthen the double-comma test with an exact-output assertion.

- Make the basePath+assetPrefix round-trip test assert lazy-exclusion by basename, not the exact modulepreload href (that URL is subject to a separate, pre-existing collectAssetTags asset-URL bug).

- Nits: 'absent/undefined map' wording; unify JS/CSS nonce-prop handling; document the process-lifetime root-realpath cache.

Investigation note: a sub-agent confirmed a separate PRE-EXISTING bug (out of scope here): under basePath + a distinct path-style assetPrefix, collectAssetTags emits modulepreload hrefs as /<basePath>/<assetPrefix>/_next/... (404) while assets serve at /<assetPrefix>/_next/...; DynamicPreloadChunks already emits the correct assetPrefix-only URL.

* fix(pages-router): serve assets from assetPrefix (not basePath) when both are set

When basePath and a distinct path/absolute assetPrefix were both configured, the Pages Router emitted asset hrefs as /<basePath>/<assetPrefix>/_next/... (and the client-nav pageModuleUrl likewise), which 404 — assets actually serve at /<assetPrefix>/_next/... . assetPrefix REPLACES basePath for asset URLs in Next.js; App Router (React bootstrapModules) and next/dynamic preloads were already correct — only the Pages Router collectAssetTags / resolveClientModuleUrl paths were wrong.

- Add assetServingUrlFromBaseAnchored(value, basePath, assetPrefix): strips the basePath segment from a base-anchored SSR-manifest value and re-anchors under the assetPrefix (no-op when assetPrefix is unset). Mirrors how next/dynamic preloads are computed.

- collectAssetTags: render <link>/<script> hrefs via the re-anchoring helper while KEEPING the base-anchored value for the lazy-chunk membership test + dedup. Thread basePath/assetPrefix from vinextConfig.

- resolveClientModuleUrl (pageModuleUrl/appModuleUrl, import()ed client-side for navigation): re-anchor the same way.

Tests: collectAssetTags re-anchoring unit tests (path/absolute assetPrefix, client entry, base-only no-op, lazy-exclusion still keyed on the base-anchored value) + an end-to-end Pages Router build with basePath:'/docs' + assetPrefix:'/cdn' that fetches every emitted asset URL and asserts 200 (the previously-missing guard). Found via the sub-agent investigation in the prior review round.

* chore(app-router): address bonk review comments on next/dynamic preloads

No behavior change — review-comment cleanup (comments + one behavior-neutral refactor).

- dynamic-preload-metadata: honor the ResolveDynamicImport `importer` arg in the plugin resolver closure instead of closing over `id` (equivalent today; removes the signature/impl footgun bonk flagged).

- dynamic-preload-metadata: expand the dynamicLoaderNode `?? modules` comment to explain the react-loadable parity (it's a harmless no-op for string-array modules), per the bonk note raised twice.

- lazy-chunks: document that computeDynamicImportPreloads intentionally does NOT subtract shared eager chunks from a boundary's preload set — harmless (browser/ReactDOM.preload/React stylesheet model all dedupe by URL) and mirrors Next.js's per-module file listing (the bonk 'redundant preloads' observation).

Already-resolved bonk items verified: the redundant installClientBuildManifestGlobals call is already guarded behind the App-Router-only else branch (prod-server.ts), and the absolute-assetPrefix CSP test already asserts the nonce on cross-origin https://cdn… preload hrefs.

---------

Co-authored-by: James <james@eli.cx>
2026-06-11 00:59:18 +01:00
James Anderson 9ba0772a2e fix(middleware): clear nextUrl.basePath for absolute paths outside basePath (part of #1830) (#1872)
* fix(middleware): clear nextUrl.basePath for absolute paths outside basePath (part of #1830)

* fix(middleware): reconcile NextURL basePath tests and App Router regression

Address two blocking issues from ask-bonk review on #1872:

1. Update 10 unit tests in tests/shims.test.ts that used basePath-stripped
   URLs (e.g. http://localhost/dashboard with basePath="/app") — these tests
   encoded the old incorrect behavior where basePath was always set from
   config regardless of the URL. Switch them to prefixed input URLs
   (http://localhost/app/dashboard) to match the new correct semantics.

2. Fix App Router regression: createNextRequest in middleware-runtime.ts was
   receiving normalizedPathname already stripped of basePath (App Router
   passes cleanPathname), so the NextRequest URL had no basePath prefix and
   _stripBasePath incorrectly cleared basePath to "". Fix by applying
   addBasePathToPathname before constructing the URL, mirroring the
   un-stripped URL that Next.js's adapter always passes to middleware.

Also use addBasePathToPathname helper in prod-server.ts and deploy.ts
closures instead of duplicating the root-path edge-case logic.

* test(middleware): fix stale test assertions broken by basePath wrapper change

Update 9 tests in deploy.test.ts that checked for the old simple runMiddleware
passthrough ('runMiddleware: typeof runMiddleware === "function" ? runMiddleware : null')
which no longer matches the generated code after the basePath re-add wrapper was
introduced in the deploy adapter.

Fix 1 test in app-route-handler-runtime.test.ts that incorrectly expected NextURL
to re-add the basePath prefix to a URL that was already stripped of it. Per
getNextPathnameInfo semantics (the fix this PR implements for #1830), basePath is
only set when the pathname actually starts with the configured prefix — a stripped
URL stays stripped.

* fix(middleware): gate basePath re-add on in-basePath state and restore route handler URL parity

- Fix the missed import assertion in tests/deploy.test.ts (the generated
  entry now imports addBasePathToPathname alongside hasBasePath/stripBasePath).
- Gate the basePath re-add in createNextRequest on a new hadBasePath option:
  the unconditional re-add regressed the Pages out-of-basePath flow by
  re-prefixing absolute-path requests the adapters deliberately left bare,
  making middleware see nextUrl.basePath === "/root" instead of "". The
  flag defaults to URL-derived (correct for prod/deploy Pages adapters) and
  is asserted true by callers that pass pre-stripped URLs (App Router,
  dev server).
- Re-add basePath in createTrackedAppRouteRequest so App Route handlers see
  the original prefixed request.url / nextUrl.href and an active
  nextUrl.basePath, matching Next.js (the routing layer strips basePath
  before handlers run).
- Re-derive the active basePath from the configured value in
  NextURL._stripBasePath on every parse, so href reassignment toggles
  basePath like Next.js NextURL.analyze().
- Add unit tests covering the App Router nextUrl.basePath re-add, the Pages
  in-/out-of-basePath flows, matcher evaluation against stripped paths, and
  href re-derivation.

* refactor(middleware): extract shared wrapMiddlewareWithBasePath helper

The runMiddleware basePath re-add closure was duplicated verbatim in
prod-server.ts and the generated worker entry in deploy.ts. Extract it
to wrapMiddlewareWithBasePath in server/pages-request-pipeline.ts (both
adapters already import from that module) to keep the two adapters in
sync.

* test(middleware): add unit coverage for wrapMiddlewareWithBasePath

Covers the helper's gating contract directly: pass-through when
hadBasePath is false or basePath is empty, prefix re-add (preserving
query, headers, ctx, and opts), and idempotent re-add for an
already-prefixed URL.
2026-06-11 00:54:56 +01:00
Jerry Zhao e4ac3b6778 refactor(optimize-imports): drop dead packageName/resolveEntry params from buildBarrelExportMap (#1895) 2026-06-11 00:28:28 +01:00
Jerry Zhao 80b858acc6 refactor(optimize-imports): normalize resolvePackageEntry paths via normalizePathSeparators (#1894) 2026-06-11 00:19:54 +01:00
Jerry Zhao 31fed9ae21 refactor(optimize-imports): resolve barrel re-export paths with path.posix (#1892) 2026-06-11 00:19:41 +01:00
James Anderson 206b016303 fix(cloudflare): update cache adapter jsdoc and examples (#1898)
* docs: remove cdn adapter from examples

* update adapter docs
2026-06-10 19:16:11 +00:00
Divanshu Chauhan (divkix) 743f252b7a refactor(isr): centralise HIT/STALE/MISS + Cache-Control decision in isr-decision.ts (#1883)
* refactor(isr): centralise HIT/STALE/MISS + Cache-Control decision in isr-decision.ts

Add server/isr-decision.ts as the single owner of the ISR cache policy
decision across all four call sites (app-page-cache, app-route-handler,
pages-page-data, dev-server). Every cache disposition, background-regen
flag, and Cache-Control string now flows through decideIsr() or its MISS
helpers.

Also eliminate all hardcoded Cache-Control literals outside cache-control.ts
(NEVER_CACHE_CONTROL, NO_STORE_CACHE_CONTROL, and raw s-maxage strings
in dev-server.ts, pages-page-response.ts, pages-page-handler.ts).

One deliberate behaviour change: dev STALE responses now emit
s-maxage=0, stale-while-revalidate (matching prod Pages Router) instead
of s-maxage=<revalidate>, stale-while-revalidate. This closes a dev/prod
parity gap that was masked by the duplication.

Closes #1783

* fix(isr): un-export IsrDisposition and IsrPolicyKind (knip unused-export)

* docs(isr): tighten isr-decision docstring and hoist resolveRevalidate

* refactor(isr): pass cacheState directly to decideIsr, drop hasUsableValue/isStale

Replace the two-field hasUsableValue+isStale decomposition with a single
cacheState: "HIT" | "STALE" | "MISS" parameter that callers already have.
Also remove the before/after equivalence table from the module docstring,
which is only relevant during the migration window.

All five call sites updated; tsc --noEmit passes with no errors.

* test(isr): update decideIsr tests for cacheState
2026-06-10 15:35:40 +01:00
Nathan Nguyen a043347c30 refactor(app-router): extract browser history traversal into AppBrowserHistoryController (#1884)
* refactor(pages-router): scope PagesReadinessNextData to its module

PagesReadinessNextData was exported but only referenced inside
pages-readiness.ts, as the return-type annotation of
buildPagesReadinessNextData. No other module imports the type by name, so the
export is dead public surface that knip flags as an unused exported type.

Drop the export keyword so the alias stays a module-local type. Callers consume
buildPagesReadinessNextData's inferred return type, so the public behavior and
the readiness shape are unchanged.

* refactor(app-router): extract browser history traversal into AppBrowserHistoryController

The App Router browser entry owned a coherent cluster of history-traversal
responsibilities inline: current/next traversal-index state, index allocation
and commit bookkeeping, push/replace/traverse/hash-only history-state writes,
hash-only scroll-metadata stripping, previousNextUrl/BFCache id synchronization,
restorable-snapshot resolution, and the initial hydrated history writes. That
made app-browser-entry.ts more than browser-runtime bootstrap glue and left
history-traversal behavior hard to unit test directly.

Move that cluster behind a typed AppBrowserHistoryController under server/. The
controller owns the traversal-index state machine, history metadata writes,
BFCache epoch and snapshot invalidation through RestorableClientStateController,
hash-only scroll stripping, restorable-snapshot candidate resolution, and the
traversal-index commit that runs after, and only after, an injected approved
visible-restore callback succeeds. Browser-history I/O is injected so the
controller is exercised without a DOM.

Keep the ownership boundary intact. AppBrowserNavigationController remains the
only authority for approved visible router-state commits: the entry still owns
the restoreHistorySnapshotVisibleState() call, stageClientParams(), and
commitClientNavigationState(). The history controller resolves history facts and
delegates visible restoration through the injected approved-commit callback. It
never imports applyApprovedVisibleCommit(), sets router state directly, or
bypasses the ApprovedVisibleCommit boundary.

Behavior is unchanged: the moved logic is identical, including the basePath
target checks and server-action cache invalidation semantics. Adds focused
controller unit tests for index allocation, hash-only scroll stripping, epoch
sync, and approved-restore delegation. The #1743 scroll-restoration,
hash-popstate, autoscroll, and navigation E2E suites stay green.

Closes #1818.
2026-06-10 15:25:00 +01:00
Jerry Zhao 6107113fa9 fix(fonts): normalize shims dir so shim-skip guards match on Windows (#1885) 2026-06-10 14:25:15 +01:00
Jerry Zhao b3215cea30 fix(check): normalize scanned file paths to forward slashes on Windows (#1887) 2026-06-10 14:20:41 +01:00
Jerry Zhao 2884125070 fix(shims): use path.posix.join in resolveShimModulePath for Windows (#1886) 2026-06-10 14:20:23 +01:00
James Anderson 7d502f6de5 fix(scss): resolve tilde (~) imports from node_modules and project root (#1881)
* fix(scss): resolve tilde (~) imports from node_modules and project root (#1825)

Next.js (via sass-loader's webpackImporter) supports two tilde import
forms in SCSS: `~pkg/path` (node_modules) and `~/path` (project root).
Vite's built-in Sass resolver does not strip the `~` prefix, so any
SCSS using tilde imports fails with "Can't find stylesheet to import".

This adds `createSassTildeImporter(root)` – a Sass FileImporter
(modern API) injected first in `css.preprocessorOptions.scss.importers`
for every vinext project. It:

- Returns `null` for non-tilde URLs, passing through to Vite's resolver
- `~/path` → resolves relative to the Vite project root
- `~pkg/path` → fast-path checks `<root>/node_modules/<pkg>` directly;
  falls back to `createRequire`-based resolution for hoisted pnpm graphs,
  yarn PnP, and workspace monorepos

The importer is always injected (not just when sassOptions is set) so
test fixtures that don't configure sassOptions still get tilde support.

Fixes #1825

Affected tests:
- test/e2e/app-dir/scss/npm-import-tilde (tilde imports)
- test/e2e/app-dir/scss/nm-module (CSS module from node_modules)

* fix(scss): fix lint errors in sass-options test (unused import, unsafe optional chaining)

Remove unused `import fs from "node:fs"` and replace unsafe optional-chaining
casts (`opts?.scss?.importers as any[]`) with guarded local variables so
oxlint's no-unsafe-optional-chaining rule is satisfied. Also applies the
formatter fix already caught by `vp check --fix`.
2026-06-09 15:43:20 +01:00