Repository navigation
fix(build): align SSR CSS asset paths - #2291
Conversation
|
/bigbonk review for issues |
commit: |
|
Performance benchmarksCompared 0 improved · 0 regressed · 6 within ±1.5%
View detailed results and traces 🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head |
|
@james-elicx Bonk workflow was cancelled. View workflow run · To retry, trigger Bonk again. |
|
/bigbonk review for issues |
There was a problem hiding this comment.
Review: fix(build): align SSR CSS asset paths
I reviewed the change against the Next.js parity reference and verified behavior locally. This is a solid, well-scoped fix. Summary below.
Correctness — looks good
-
Root cause is addressed correctly. The
vinext:css-url-assets-defaultsplugin now appliescreateClientAssetFileNames(resolveAssetsDir(...))to thersc/ssrenvironments, so SSR-emitted CSSurl()references land under/_next/static/media/instead of the bare/_next/static/<name>-<hash>.<ext>shape. This matches the client environment exactly — both callcreateClientAssetFileNameswith the sameresolveAssetsDir(nextConfig.assetPrefix ?? "")expression (index.ts:1844vsindex.ts:3117), so the emitted path and the content hash align, and the test'sexpect(serverAssetUrls).toEqual(clientAssetUrls)+ on-diskdist/clientexistence check holds. -
Hook ordering is safe.
configEnvironmentreadshasAppDirandnextConfig, both populated by the mainconfighook. Vite runs allconfighooks beforeconfigEnvironment, and the unit test exercises this (callsmainPlugin.config()thenconfigEnvironment("ssr", ...)), so the dependency is real but correctly ordered and covered. -
No conflict with the RSC framework-chunk output.
createRscFrameworkChunkOutputConfigsets onlycodeSplitting/manualChunks, notassetFileNames, so Vite's deep-merge keeps both. Good. -
User override is respected. The
hasAssetFileNamesguard (handling both array and objectoutput) correctly bails when the user set their ownassetFileNames, matching the stated goal and the new "custom assetFileNames → null" test case.
Next.js parity
Confirmed the ported behavior matches test/e2e/app-dir/scss/url-global/url-global.test.ts — Next.js serves CSS url() assets under /_next/static/media/ and verifies they resolve. The fix brings SSR output in line with that contract.
Validation (ran locally)
vp test run tests/build-optimization.test.ts→ 149 passedvp test run tests/css-url-assets.test.ts→ 9 passedvp check packages/vinext/src/index.ts tests/css-url-assets.test.ts tests/build-optimization.test.ts→ clean (format, lint, types)
Minor observations (non-blocking)
-
Array
outputwrite path. The read side detectsassetFileNamesacross array elements, but the write side always returns a single objectoutputviawithBuildBundlerOptions. If a user supplied an arrayoutputfor rsc/ssr without anyassetFileNames, merging an object-shapedoutputinto an array-shaped one could behave unexpectedly. This is an extremely rare config for server environments and matches existing patterns in the file, so it's fine to leave — just flagging it. -
Test coverage shifted from plain multi-env to Cloudflare-only. The App Router integration test was rewritten to build through
@cloudflare/vite-plugin(which faithfully reproduces the reported scenario in #2290). The fix itself is Cloudflare-independent (configEnvironmentfor rsc/ssr doesn't check for the Cloudflare plugin), so the non-Cloudflare multi-env path is no longer directly asserted for SSR-CSS parity. Acceptable since the new test reproduces the actual bug report, but worth noting in case a future regression slips into a non-Cloudflare build.
Overall: correct, well-tested, and consistent with repo conventions and Next.js behavior. LGTM.
|
Review posted on PR #2291. Summary of my findings: Verdict: LGTM — correct, well-tested, no blocking issuesThe fix correctly resolves #2290 (SSR CSS Key correctness checks (all pass):
Parity: Matches the ported Next.js test ( Validation (ran locally): both test files pass (149 + 9), and Minor non-blocking notes:
|
|
/bigbonk re-review |
Re-review: fix(build): align SSR CSS asset pathsRe-reviewed after the new commit Verified locally:
The core fix is still correct: rsc/ssr now use the identical One real issue: the array-
|
|
Re-review posted on PR #2291. SummaryThe new commit The core fix remains correct — rsc/ssr now use the identical One real (but very narrow) issue I found: the new array- This is an extremely rare config (array |
|
/bigbonk re-review |
There was a problem hiding this comment.
Re-review: fix(build): align SSR CSS asset paths
Re-reviewed after the new commit 5b70139 ("fix(build): preserve array output configuration"). This commit directly addresses the one real issue I flagged in my previous re-review — the array-output write path being defeated by Vite's mergeConfig.
The array-output issue is resolved
The author took option 1 from my prior review: drop the array-augmentation branch entirely and bail out when output is an array.
// Vite concatenates arrays returned from config hooks rather than
// merging output entries by index, so an array-shaped user config
// cannot be safely augmented here. Preserve it unchanged.
if (Array.isArray(output) || output?.assetFileNames !== undefined) return null;This is correct:
- The
mergeConfigarray-concatenation footgun is gone — we never return an arrayoutput, so there's nothing for Vite to mis-merge. - The comment accurately documents why (index-merge is impossible via
mergeConfig), so the constraint won't be accidentally reintroduced. - The object-
outputpath is unchanged and still correct: it returns{ rolldownOptions: { output: { assetFileNames } } }, whichmergeConfigdeep-merges cleanly into a user's object-shaped output. - The user-override bail-out (
output?.assetFileNames !== undefined) is preserved.
The unit test was updated to assert the new behavior — an array-shaped output now expect(...).toBeNull() (tests/build-optimization.test.ts:913-925). This replaces the previously misleading assertion that checked the raw mapped return value (which never went through mergeConfig and gave false confidence). The test now reflects what actually happens in a real build.
Trade-off is acceptable
The behavioral consequence: if a user supplies an array output for the rsc/ssr environment without assetFileNames, vinext no longer injects the Next-compatible static/media naming for those environments, so SSR CSS url() assets would fall back to the default path. This is an extremely rare config for a server environment, it's strictly safer than the previous (broken) array branch which produced duplicate output passes, and the common object path — the one that actually fixes #2290 — is correct and well-covered. Bailing out cleanly is the right call.
Verified locally
vp test run tests/build-optimization.test.ts tests/css-url-assets.test.ts→ 160 passed (149 + 11)vp check packages/vinext/src/index.ts tests/build-optimization.test.ts tests/css-url-assets.test.ts→ clean (format, lint, types)
Verdict: LGTM — ship it
The core fix remains correct (rsc/ssr use the identical createClientAssetFileNames(resolveAssetsDir(nextConfig.assetPrefix ?? "")) as the client env, so SSR CSS url() assets land under /_next/static/media/ and resolve against dist/client), and the one outstanding issue from my prior review is now properly resolved with a matching test. No remaining blocking or non-blocking concerns.
|
Re-review posted on PR #2291. SummaryThe new commit The author took option 1: drop the array-augmentation branch and bail out ( Verified locally:
The core fix remains correct (rsc/ssr use the identical |
Summary
static/mediaasset naming to App Router RSC and SSR build environmentsassetFileNamesconfigurationdist/clientFixes #2290.
Next.js parity
Ported behavior from
test/e2e/app-dir/scss/url-global/url-global.test.ts, which expects CSSurl()assets under/_next/static/media/and verifies those URLs are served.Validation
vp test run tests/css-url-assets.test.ts tests/build-optimization.test.ts(158 passed)vp check packages/vinext/src/index.ts tests/css-url-assets.test.ts tests/build-optimization.test.tsgit diff --check