Commit Graph

2 Commits

Author SHA1 Message Date
Nathan Nguyen 16cbac3053 fix(build): emit Next client runtime manifests (#1735)
* fix(build): emit Next client runtime manifests

Next.js serves /_next/static/<buildId>/_buildManifest.js as a build asset, including when basePath is folded into assetPrefix. vinext already routed prefixed static assets correctly, but the production client build never wrote the low-priority runtime manifest files, so valid Next.js probes 404ed under basePath.

Emit _buildManifest.js and _ssgManifest.js during the client build under the resolved assets directory and build ID. Keep the manifest content scoped to the client-visible rewrite shape vinext supports and add regression coverage for the upstream basePath test case.

* fix(build): preserve all rewrite fields except external destination in client manifest

* fix(build): restore Next.js rewrite manifest shape

Tighten ClientRuntimeRewrite to { source, destination?, has? } so the
emitted client manifest matches Next.js's normalizeRewrite output
exactly (drops missing, locale, basePath). Drop the path.basename
clientDir fallback in the runtime manifests plugin so client-env
detection matches every other hook in the file. Extend the basePath
end-to-end test to also fetch _ssgManifest.js.
2026-06-05 21:50:01 +01:00
Nathan Nguyen b1f2e57bc4 fix(pages): preserve import.meta.url source paths (#1598)
* fix(pages): preserve import.meta.url source paths

Pages Router production bundles previously left direct import.meta.url expressions for the bundler to evaluate from generated output. Server renders could expose dist/server/entry.js, and prerendered Pages output could miss the client entry needed for hydration to replace the server value with the Turbopack-style browser source URL.

The fix rewrites direct import.meta.url reads in user modules to source-file URLs at transform time, keeps new URL asset bases intact, and loads the Pages client entry from the build manifest for Node production and prerender servers.

Regression coverage ports the Next.js import-meta deploy test, including the prerender and hydrated browser path.

* fix(tests): run import.meta browser coverage in e2e

The import-meta regression test launched Playwright from a Vitest integration shard. That shard does not install Playwright browser binaries in CI, so it failed before exercising the runtime behavior.

Move the browser assertion into the existing pages-router-prod Playwright project, keep the lower-boundary server and client chunk assertions in Vitest, and cache the import-meta plugin root paths after an early source-text bailout to address review feedback.

* refactor(import-meta-url): canonicalize each module once per transform

The transform path canonicalized the same module id twice: once in the
eligibility check and again when computing the replacement value, so every
rewritten module paid for two fs.realpathSync.native() syscalls.

The eligibility check now returns the canonical id and threads it through to
the value computation, leaving a single realpath per module.

Also widens the extension match to .cts/.mts/.cjs and documents that the
new URL() skip only covers the bare URL identifier, matching Vite's own
asset-detection scope.

* test(pages): drop unrelated prerender from top-level-await setup

The top-level-await production test ran runPrerender in its setup, but the
assertions pass identically whether the routes are prerendered or rendered on
demand. The step added unrelated build work to a test that is not about
prerendering or client-entry injection.

* fix(pages): share client entry fallback

* fix(import-meta-url): address PR review feedback

- Handle ChainExpression (import.meta?.url) in new URL() asset-detection
  skip so the optional-chain variant preserves Vite asset resolution
- Add explicit ChainExpression check in visit() to avoid fragile
  reliance on coincident inner-node start/end ranges
- Add test for new URL('./file', import.meta?.url) preservation
- Fix decodeHtmlText entity ordering (&amp; before &quot;) in both
  unit and E2E test helpers
- Add doc comments: excluded prefixes rationale, node_modules
  early-exit optimization intent

* fix(pages): select client entry by marker in build manifest

findClientEntryFileFromManifest returned the first chunk flagged
isEntry, but a client build can emit several entry chunks (client
entry plus instrumentation/middleware) and manifest order is not
guaranteed. The on-disk fallback already disambiguates by the
vinext-client-entry / vinext-app-browser-entry marker; apply the
same check to the manifest path so both lookups agree, falling back
to the first entry only when nothing is marked.

* refactor(pages): address review feedback on client-entry/import-meta-url

- prod-server: hoist findClientEntryFile out of the manifest if/else
  since it already handles a missing manifest via the on-disk fallback
- import-meta-url: document the two known limitations (destructured
  access, aliased new URL() base) that match Vite's own behavior
- import-meta-url: drop the dead visit(value.callee) for new URL() —
  the callee is always the bare URL identifier

---------

Co-authored-by: James <james@eli.cx>
2026-05-31 11:37:09 +01:00