* 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.
* fix(assets): default assetsDir to _next/static (Next.js parity)
Closes#1337. Supersedes #1383.
vinext's default `assetsDir` was Vite's historical `assets/`, so URL emission
(`/_next/static/...` via `resolveAssetUrlPrefix("")`) and on-disk layout
(`dist/client/assets/...`) disagreed in the empty-`assetPrefix` case. The
`build.assetsDir` and `experimental.renderBuiltUrl` Vite overrides only
applied when `assetPrefix` was configured, leaving the no-prefix branch
serving from a different path than the URL contract Next.js's client
runtime and test harness assert against.
This commit flips the default to Next.js's canonical layout:
- `resolveAssetsDir("")` returns `_next/static` (was `assets`)
- `build.assetsDir` is now set unconditionally from `resolveAssetsDir`
- Vite's default `base + assetsDir` composition produces correct URLs
in the no-prefix case; `renderBuiltUrl` stays gated on `assetPrefix`
because it's only needed for the configured cases
- Drops the legacy `/assets/` branches in prod-server (3 sites) and
static-file-cache (hard cutover — see PR description for rationale)
- Updates `_headers` generation, precompress default, fonts plugin
`DEFAULT_ASSETS_DIR` to match the new default
With the layout aligned, invalid `_next/static/*` requests naturally
return plain-text `404 + "Not Found"` from the static-file layer instead
of falling through to the page renderer (which would produce an HTML
404 with bootstrap scripts and CSS). This replaces #1383's parity
short-circuit with the natural code path:
- Node prod-server (App + Pages branches): missing asset under
`resolveAppRouterAssetPath` returns `text/plain; charset=utf-8` 404
- Cloudflare worker entry: `isNextStaticPath` recognises asset-shape
after ASSETS-binding misses; returns `notFoundStaticAssetResponse`
Mirrors Next.js: packages/next/src/server/lib/router-server.ts.
Adds `tests/invalid-static-asset-404.test.ts` (3 App Router + 3 Pages
Router cases — no prefix / basePath / assetPrefix) ported from Next.js
e2e suites. Updates 11 source files + 12 test files; 914+ tests pass
in the touched suites (asset-prefix, app-router, pages-router, deploy,
font-google, static-file-cache, serve-static, precompress, features,
routing, isr-cache, build-optimization, app-rsc/ssr, standalone,
middleware, shims).
Ported from Next.js:
- test/e2e/invalid-static-asset-404-app/*.test.ts
- test/e2e/invalid-static-asset-404-pages/*.test.ts
* fix(e2e): update cloudflare-pages-router hydration spec for _next/static
* PR #1411 approved. Clean fix, 2 nits.
Co-authored-by: james-elicx <james-elicx@users.noreply.github.com>
* refactor(assets): derive isHashed checks from ASSET_PREFIX_URL_DIR
Replace hardcoded '_next/static' string literals in runtime code paths
with the ASSET_PREFIX_URL_DIR constant so the asset URL convention has
a single source of truth.
- server/prod-server.ts isHashed: pathname.includes(`/${ASSET_PREFIX_URL_DIR}/`)
- server/prod-server.ts public-dir guard: startsWith(`/${ASSET_PREFIX_URL_DIR}/`)
- server/static-file-cache.ts isHashed: both startsWith + includes derived
- plugins/fonts.ts DEFAULT_ASSETS_DIR = ASSET_PREFIX_URL_DIR
Behavioural no-op — the constant is '_next/static' so the resolved
strings are identical. Centralises the URL contract so future changes
to ASSET_PREFIX_URL_DIR (or a refactor that derives it from build
config) flow through to every consumer.
Doc-comment references to '_next/static' left in place — they
describe the canonical value for human readers and are not code paths.
---------
Co-authored-by: ask-bonk[bot] <ask-bonk[bot]@users.noreply.github.com>
Co-authored-by: james-elicx <james-elicx@users.noreply.github.com>