Conversation
Vite's vite:css-post plugin emits the extracted CSS assets in its own generateBundle hook, which runs after the enforce:'pre' plugins. With build.cssCodeSplit: false the whole stylesheet is emitted there (and nowhere else), so the adapter's generateBundle ran before any CSS asset existed in the bundle. It then fell back to appending on disk in writeBundle without rehashing the filename, so a StyleX-only edit changed the CSS bytes while the content-hashed filename stayed the same and browsers/CDNs kept serving stale stylesheet against the new class names. Run the adapter's generateBundle in post order so it executes after vite:css-post has emitted the single stylesheet, making the existing replaceCssAssetWithHashedCopy path work for single-stylesheet builds. Fixes facebook#1889
|
Hi @0x5t4l1n! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks! |
|
@0x5t4l1n is attempting to deploy a commit to the Meta Open Source Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Copilot review overview
🔵 Needs a closer look
The regression test does not exercise Vite’s hook scheduler or verify updated hashed asset references.
Review effort: Lite
Findings: None
What changed in this PR
Fixes stale CSS filenames in Vite single-stylesheet builds by running StyleX CSS processing after Vite emits the stylesheet.
Changes:
- Runs
generateBundlewith post-order execution. - Adds tests for stylesheet rehashing and hook ordering.
| File | Reviewed changes |
|---|---|
packages/@stylexjs/unplugin/src/vite.js |
Applies post-ordered CSS asset replacement and rehashing. |
packages/@stylexjs/unplugin/__tests__/unplugin.test.js |
Adds coverage for hook ordering and single-stylesheet rehashing. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks! |
What changed / motivation ?
Fixes
@stylexjs/unplugin's Vite adapter for single-stylesheet builds (build.cssCodeSplit: false): a StyleX-only edit (e.g. changing apaddingvalue) changed the CSS content but left the content-hashed stylesheet filename unchanged, so browsers/CDNs kept serving the stale stylesheet against the new class names.Root cause. Vite's
vite:css-postplugin emits the extracted CSS assets in its owngenerateBundlehook, which runs after theenforce: 'pre'plugins. WithcssCodeSplit: falsethe entire stylesheet is emitted there — and nowhere else. The adapter'sgenerateBundleran earlier (it lives on a pre-enforced plugin and had no hook-level ordering), so the bundle contained no CSS asset yet; the adapter then fell back to appending the StyleX CSS on disk inwriteBundle, which appends but never rehashes the filename.Fix. Run the adapter's
generateBundlewithorder: 'post'so it executes aftervite:css-posthas emitted the single stylesheet. The existingreplaceCssAssetWithHashedCopypath then applies the same rehashing already used by code-split builds. This matches the reporter's own diagnostic experiment in #1889 — the filenames produced with the fix (style-B2ydcg4O.css/style-DmGQdaq2.css) match exactly.Linked PR/Issues
Fixes #1889
Additional Context
Reproduction against published
@stylexjs/unplugin@0.19.1+ Vite 8.3.0 (4 builds: baseline, unchanged, stylex-onlypadding16 → 32, plain-CSSmargin24 → 40):Before (0.19.1, bug):
assets/style-CW4HsblT.csssha25f2e455…assets/style-CW4HsblT.csssha3b00d50c…← same filename, different bytesAfter (this fix):
assets/style-B2ydcg4O.csssha25f2e455…assets/style-DmGQdaq2.csssha3b00d50c…← filename changes with the bytesassets/style-i818Skdl.csssha56e1ff21…<link>and.vite/manifest.jsonboth reference the new hashed file; the CSS containspadding-top: 32pxTests. Added a
Vite single-stylesheet builds (cssCodeSplit: false)describe block topackages/@stylexjs/unplugin/__tests__/unplugin.test.js: one test pins theorder: 'post'hook contract, one drives the rehash path against a single emitted stylesheet. Full unplugin suite: 22/22 pass; eslint + prettier clean.Pre-flight checklist
Contribution Guidelines