vite build 丢 CSS、dev 正常:rolldown #8804 的 side-effect 去重打破了 vite_ruby 的两层 manifest 假设
现象
从 vite 8.0.1 / rolldown-rc10 升级到 vite 8.0.3 / rolldown-rc12 后,一批自动化测试失败:最终构建产物里缺少 CSS 和 JS。手动用 dev server 测试正常,只有 vite build 出问题。问题从 vite 8.0.2 / rolldown-rc11 起出现。
表现:JS 看着没问题,CSS 没了
最终 JS 输出看起来是 OK 的——被删掉的行出现在了别处。真正的后果是:通过它们 import 的 CSS 也被一并移除了。
一个具体例子是点击链接打开 modal:opened class 会正常加上,但因为 CSS 没了,modal 仍然处于隐藏状态。另外还观察到图片尺寸异常。
8.0.1 与 8.0.3 构建产出的最终 CSS 文件本身是相同的,差别在于 side-effect import 被移除,导致部分 CSS 没有被加载。
定位:逐个 override rolldown commit
维护者的建议是逐个用 overrides 指向不同的 rolldown commit,确认问题从哪个版本开始出现:
最后确认 68c7bf5 是 WORKING 的,问题由 rolldown PR #8804 引入。
根因:不是 rolldown 的 bug,是下游工具的假设被打破
报告者调查后认为,这可能不是 Rolldown 本身的 bug,而是另一个工具的假设不再成立。
他们使用 vite-plugin-ruby(vite_ruby),它通过 .vite/manifest.json 做映射:
application.ts→application-fif23f3.jsapplication.scss→application-f32f23.css
vite_ruby 假设所有副作用都被提升到 tree-shaking 链的顶部两层,也就是入口或直接 import 的依赖。相关代码见 vite_ruby/lib/vite_ruby/manifest.rb#L27-L37。
这个假设在 Rollup 和 vite 8.0.2 之前一直成立。从 #8804 起,side-effect import 在顶层被去重,被留在更深的路径下,于是 vite_ruby 没有在浏览器里 require 它们,CSS 因此缺失。
这也解释了为什么 dev 正常:dev 环境下 vite_ruby 直接交给 vite dev,后者会正确递归 manifest,找出全部文件。
维护者的回应是:这个假设在你的 app 里碰巧成立,但并不通用。
修复
vite_ruby 作者发布了修复版,改为递归依赖树查找全部 CSS,问题解决。
处理这类问题的两条路:下游工具改成递归读取 manifest(vite_ruby 走的就是这条),或者在升级窗口里固定 rolldown / vite 版本,等消费 manifest 的一方跟进。