☰
Vite 8.0 发布:Rolldown 引擎重构构建链路,迁移指南与实测
2026/10/2 4:04:55 网站建设 项目流程

Vite 8.0 的正式版本发布那天,我朋友圈里好几个做前端工程化的朋友都转发了同一条消息,配文出奇一致:"这次是真的大更新。"说实话,我一开始也以为只是例行的大版本号推进。Vite 从 2.0 之后,3、4、5、6、7 每一代都在优化,但说白了都是渐进式改良,真正动骨架的次数并不多。直到我把自己负责的两个项目升到 8.0,实际跑了几天之后,才确认这次确实不一样。

如果你正在用 Vite,不管你是维护一个几十万行代码的中后台项目,还是在维护自己的组件库、文档站,这篇文章应该能帮你省下不少摸索时间。我会先讲清楚 Vite 8.0 到底动了哪些底层东西,然后给出一份可以直接照做的迁移步骤,最后把我这一个月实际踩过的坑、实测到的数据一并放出来。这也是"2.0 以来最大更新"这个说法的来源:上一次出现同级别的变化,还是 Vite 2.0 引入 esbuild 做依赖预构建的时候。那一次改变了开发服务器的启动方式,这一次改变的是整个打包链路。

1. 为什么说这是 2.0 以来最大的更新

Vite 自诞生那天起,就有个非常讨巧的双引擎设计:开发阶段用 esbuild 做依赖预构建,把 node_modules 里成千上万的模块预先打包成浏览器能直接加载的 ESM 格式,换取极快的冷启动;生产构建则交给 Rollup 出正式产物。这个分工在当年是非常聪明的选择,esbuild 快是快,但产物没有做生产级优化,比如代码分割的精细度和 tree-shaking 的深度都不够,所以让更成熟的 Rollup 来兜底。

1.1 之前的大版本都在"改良",这次是"换心"

但双引擎方案的成功,也埋下了一个长期隐患:开发和生产是两套行为。同一个项目,开发时跑的是 esbuild 处理过的模块,构建时跑的是 Rollup 重新解析的模块。大多数时候二者表现一致,可一旦遇到依赖处理边界、钩子执行顺序、模块副作用标记不一致的场景,就会出现"开发好好的,一打包就报错"的玄学问题。

Vite 3 到 Vite 7 这几代,核心工作基本都围绕一件事:在不推翻双引擎的前提下做修补。比如 Vite 5 优化了服务器启动时的模块扫描,Vite 6 推出了环境 API(Environment API),Vite 7 把 Rolldown 作为可选项引入构建链路。这些都很重要,但没有动到骨架本身。

Vite 8.0 做的事情,一句话就能讲完:把整套打包核心换成了 Rolldown。这是一个用 Rust 写的打包器,完全兼容 Rollup 的插件接口,同时能以接近 esbuild 的速度完成生产构建。从 8.0 开始,Vite 的开发与生产构建终于跑在同一个引擎上,此前"开发/生产行为不一致"的根源被直接拔掉了。

1.2 谁最应该关注这次升级

如果你的项目属于下面几类,我建议重点看后面的迁移章节。

第一类是大型中后台项目。这类项目依赖特别多、体积大,平时开发冷启动可能十几秒,生产构建经常几十秒甚至几分钟。Rolldown 接管后,构建耗时的下降是目前所有优化手段里最明显的。

第二类是维护组件库、工具库的人。组件库对构建产物格式要求更复杂,既要 ESM 又要 CJS,有时候还要单独出类型声明。Rolldown 对多格式输出的支持比 Rollup 更顺手,构建速度也有明显提升。

第三类是 SSR 项目用户。Rolldown 对 SSR 外部化的处理更彻底,服务端产物体积和服务启动速度都有改善。

至于纯静态营销页、很小的一两个页面站点,Vite 8.0 当然也能用,但感知不会太强。不用慌,升级成本也不高,后面会讲。

2. Rolldown:换掉打包内核到底意味着什么

既然最大变化是换引擎,我们得先搞清楚 Rolldown 改变了什么。要说明白这个问题,得把 Vite 从 2.0 到 8.0 的引擎演化路径简要梳理一下。

2.1 从 esbuild 预构建到 Rolldown 预构建

Vite 2.0 时代的开发服务器,启动时要做两件事:一是扫描入口模块,二是对依赖做预构建。预构建之前一直由 esbuild 负责,它把 CJS 格式的依赖转换成 ESM,同时把上千个小模块合并成少数几个大模块,从而减少浏览器发起的请求数。

Vite 8.0 里,预构建已经默认切换到 Rolldown。最直观的感受是预构建产物体积变小了,因为 Rolldown 是按依赖的模块图去做合并,能处理更复杂的依赖关系,而 esbuild 的合并策略相对简单。以我自己一个项目为例,预构建产物目录从 160MB 降到了 110MB 左右,启动时扫描这些产物文件的时间自然也跟着变短。

另一个值得提的细节是重新构建的触发条件。以前依赖预构建的失效判断靠的是追踪 node_modules 相关文件的 mtime,偶尔会出现改了依赖但缓存没失效、必须手动删除 node_modules/.vite 才能解决的问题。8.0 里这部分逻辑被重写过,同样的情况我复现了三次,都没有再出现旧缓存不失效的问题。

2.2 为什么 Rust 重写能快这么多

聊到这里,很多人会问:Rust 到底凭什么快这么多?我的理解是,核心原因不在语言本身,而在并行能力和数据结构。

Rollup 跑在 JavaScript 单线程环境里,模块图建立、AST 转换、tree-shaking 这些环节很难真正并行化。Rolldown 从一开始就按多线程设计,模块解析和 Transform 可以分散到多个 worker 里同时跑,等到需要合并结果时再统一步骤。另一个关键点是,Rolldown 在 Rust 层直接维护模块图和缓存,不需要像 Rollup 那样反复在 JavaScript 对象和 AST 之间做序列化转换,省掉了大量临时对象分配和垃圾回收。

打个不严谨但好理解的比方:Rollup 像一个单线程的图书管理员,每查一本书都要把书架整个走一遍;Rolldown 则是一个多线程的仓库系统,每本书都有索引,多个管理员可以同时取书,而且仓库里直接放的是整理好的数据,不需要每次现场加工。

2.3 对插件生态的真实影响

有人听到"换核心",第一反应是插件会不会全挂掉。实际上 Rolldown 刻意兼容了 Rollup 的插件 API,Vite 主流的插件,比如 @vitejs/plugin-vue、@vitejs/plugin-react、unplugin 系列,在 8.0 里都能直接使用,这一点不用担心。

但 Rolldown 的插件机制确实比 Rollup 灵活。过去在 Rollup 里做 transform、resolve 这类钩子,经常要等整个模块图建立到一定程度才能操作;Rolldown 允许插件在更早的阶段介入,并且支持增量编译。我给自己一个私有插件加了一段 moduleParsed 阶段的转换逻辑,跑下来整体兼容性都不错。

如果项目里用了比较小众的 Rollup 插件,我的建议是先确认它是否依赖了 Rollup 的私有 API。Rolldown 兼容的是公开 API,不是内部实现。任何在 hook 里直接访问 bundle 内部对象私有字段的插件,都需要适配,这个坑后面有具体案例。

2.4 一个让我印象深刻的典型案例

我在升级后的第三周遇到了一个过去会非常头疼的问题:某个第三方库在生产构建时打出来的包,引用了它 package.json 里 exports 字段没有声明的子路径。按以前的经验,这种问题通常要靠 patch-package 或者插件里专门写 resolve 逻辑来处理。

但在 Vite 8.0 里,因为开发和构建用的是同一个解析引擎,这个问题在开发启动阶段就直接暴露出来了,错误提示里会明确告诉你这个子路径没有被 exports 字段暴露。我顺着提示改了一下依赖的引用方式就解决了。放在以前,这个问题大概率要等到 CI 构建时才会炸出来,然后来回切换版本、加日志排查半天。

这种体验层面的改善,恰恰是"开发与生产行为一致"在真实项目里的价值。它不像某个具体功能那么显眼,但能帮你省掉大量隐性排查时间。

3. Vite 8.0 里值得关注的几个新能力

引擎替换是主角,但 Vite 8.0 还顺手端上来几道配菜。这几个能力单独看可能不算惊天动地,组合在一起体验提升很明显。

3.1 Environment API 从实验转为稳定

Environment API 是 Vite 6 开始引入的实验特性,到了 8.0 已经标记为稳定。它的核心思路是让同一次构建可以针对多个运行环境分别产出,而不是像以前那样,一个项目要么配 client、要么配 ssr,想同时出两份产物还得写两套 config。

我举一个实际场景。我们内部有个 BFF 项目,前端部分需要在浏览器里跑客户端 bundle,又要给 Node 服务端出一份 SSR bundle。以前配置里要区分 build.ssr 和各种条件分支,写在同一个配置文件里,经常一不留神就互相污染。用了 Environment API 之后,可以声明若干个环境:client、server,甚至还可以加一个给边缘函数用的 edge 环境,每个环境有自己的 resolver、插件和 output 配置,互不干扰。

这个能力对微前端场景同样有价值。多个子应用共享同一套构建配置,但希望产出到不同目录,或者希望某些子应用用不同的 external,都可以通过环境级别的配置解决,不用再为每个子应用单独维护一份配置。

3.2 内置模块图可视化与分析工具

Vite 8.0 里新增了一个让我比较惊喜的地方:模块图可视化能力。以前要看某个模块为什么被打进 bundle,常规方案是装 rollup-plugin-visualizer,输出一个 HTML 分析图。现在 Vite 自己带了类似能力,执行构建时加一个参数,就能生成模块依赖关系与体积分布的 JSON,配合官方 viewer 页面查看。

另外 build 阶段还新增了耗时分析输出。我跑构建时加上 profiling 参数,结束后终端会直接打印出每个阶段的耗时排序,包括 resolve、load、transform、renderChunk 各自花费的时间,一眼就能看出瓶颈在哪。以前想拿到这类数据,得在插件里手动包一层计时逻辑,现在内置了,排查依赖解析性能问题会省很多事。

3.3 CLI 和配置层面的人性化改进

这一代还顺手清理了一批长期标记废弃的 API。启动或构建时报出的错误信息明显更具体了,不再是一段笼统的堆栈,而是直接告诉你哪个配置项、哪个 hook 用法过时了,应该替换成什么。Rolldown 对废弃 API 的警告写得很到位,照着提示改就能完成大部分迁移。

还有一个很务实的改进:配置文件里不再需要为了达到最佳性能去手动折腾一些高级参数。以前我经常要在 optimizeDeps 和 build 之间来回调参,比如某些依赖坚持要 include、某些依赖 go 两难。8.0 的默认配置在这些场景下基本都能给出合理结果,我自己的项目里几乎没再动过这些选项。

4. 从 7.x 迁移到 8.0 的完整实操记录

聊完特性,直接上干货。下面是我从 Vite 7 迁移到 8.0 的完整过程,照做基本不会出问题。

4.1 迁移前的三件事

第一,确认 Node 版本。Vite 8.0 官方要求 Node 20.19+ 或 22.12+。如果你还在用 Node 18,这一步就必须先升版本。第二,把 package.json 里所有 Vite 相关的包列出来,包括 vite、@vitejs/plugin-vue、@vitejs/plugin-react、各种 vite-plugin-*,逐一检查它们的 peerDependencies 是否支持 Vite 8。第三,清理构建机或本地环境里可能存在的全局缓存,我建议直接删掉 node_modules 和 lock 文件里的旧版本锁定,重新安装,避免把旧引擎的残留文件带进来。

这里有一条我个人的经验:迁移前先把当前项目在旧版本下的构建时长和产物体积记录一下,作为升级后的对比基线。否则升级完你会觉得快了,但说不清快了多少,后续想写评估报告或者给团队汇报都缺乏数据支撑。

4.2 升级命令与配置调整

如果项目用的是 pnpm,执行:

pnpm add -D vite@^8.0.0 pnpm add -D @vitejs/plugin-vue@latest pnpm install

npm 或者 yarn 也类似,把包管理器对应命令的版本号锁定到 8.x 即可。装完之后先别急着启动,直接跑一次构建看会不会报错。

需要留意的是几个被移除的旧选项。比如 build.terserOptions 相关的接口,以前如果你在这里配过压缩参数,现在要改成使用 rollup 原生的代码压缩插件形式;还有 optimizeDeps.keepNames 之类的旧选项,在 8.0 里已经不存在,直接在配置里删掉。启动 dev 或 build 时如果报某个配置项不识别,大概率就是命中了这类废弃项,搜一下新版的名字替换就行。

4.3 插件适配清单

我自己整理了一份兼容性速查,可以对照着看:

插件类型典型代表8.0 兼容情况
框架插件@vitejs/plugin-vue、@vitejs/plugin-react直接兼容,建议升级到最新版
按需自动导入unplugin-auto-import、unplugin-vue-components兼容,注意升级到支持 Rolldown 的版本
分析工具rollup-plugin-visualizer兼容,但 Vite 8 已内置可视化,可逐步替代
老牌 Rollup 插件@rollup/plugin-* 系列大部分兼容,小心依赖私有 API 的插件
自定义内部插件自己维护的需要逐个检查是否触碰内部实现

我给过一个判断标准:插件代码里如果出现了 bundle.xxx 这种直接操作内部对象的写法,升级后大概率要改。正确的做法是改用 this.getModuleInfo、this.emitFile 这类公开 API。

4.4 迁移后的第一轮验证

配置改完、构建通过之后,不要急着上线,先按下面的顺序验证一遍:

先跑一次完整的 production build,检查产物有没有缺模块、警告有没有异常;然后启动 dev server,重点看冷启动时间、页面路由跳转和 HMR 表现;接着把 SSR 场景单独打一遍,确认服务端产物正常。

如果以上都过了,再跑一遍团队现有的端到端测试。我的项目里,E2E 测试是最后兜底的一环,前后端联调场景覆盖得比较全,构建层面出了问题基本能在这一轮暴露出来。整套验证下来,半天时间是足够的。

5. 我踩过的坑:迁移过程中值得记录的问题

官方的迁移文档写得再清楚,也覆盖不了所有真实场景。下面这几个问题是迁移过程中我自己踩到、并且花了时间排查的,记录下来给大家做参考。

5.1 依赖预构建缓存导致的样式错乱

第一次升级后,我贪图省事,直接沿用了 node_modules/.vite 缓存目录,结果 dev server 启动后页面加载出来的样式错乱。排查后发现,旧的预构建产物是 esbuild 生成的格式,与 Rolldown 的产物混在一起了。解决办法很直接:删掉 node_modules/.vite 重新启动。之后我又试了几次,其实 Vite 8.0 检测到预构建实现变化时本身会触发重建,但如果你手动改过依赖版本、又保留了缓存,还是建议主动删一次,避免意外。

这个问题的教训是:大版本升级后,第一次启动前先清理缓存目录,这是成本最低的预防动作。别省这一步。

5.2 自定义插件在 Rolldown 下丢失 transform 结果

有个内部插件负责给特定模块注入全局变量声明,在 Rollup 下工作正常,到 Rolldown 下偶尔不生效、时好时坏。排查了很久才发现,插件里用了强制同步的 fs.readFileSync 去读一个运行时才生成的文件,时序和 Rolldown 的并行 transform 冲突了。改成在 buildStart 阶段预读内容,把结果缓存进闭包变量,问题就消失了。

这条经验很重要:如果你的插件里做了 IO 操作,尽量把 IO 前置到插件生命周期早期,不要在 transform 钩子里频繁读文件。Rolldown 的解析是并行的,IO 密集操作会拖慢构建,还容易产生不可预期的时序问题。

5.3 SSR external 的默认行为变化

另一个 SSR 项目升级后发现,服务端产物里被打进了不少本来应该 external 的 Node 内置模块和依赖。原因是 Vite 8.0 对 ssr.external 的默认判断逻辑改了,以前需要手动在列表里列出的包,现在会根据 package.json 的 type 字段自动判断,但个别老包没有正确标记,于是被打进了产物。

解决办法是把这些包显式加回 ssr.external 配置,同时在 ssr.noExternal 里放行那些确实需要被打包的 ESM-only 依赖。如果你在升级后看到"X cannot be resolved"或者产物体积突然变大,优先怀疑这个方向。

5.4 一个老插件卡在 Rollup 私有 API 上

我们项目里有一个用了两年的老插件,直接读取了 Rollup 内部模块图的私有数据结构,升级后在 Rolldown 环境下运行行为异常。处理过程比较费劲,因为文档里不会写这种用法。最终的解决路径是:先在社区 GitHub issues 里搜这个插件的名字,看有没有人提交过兼容 Roldown 的 issue;如果有就等更新,没有就必须自己改。我们把所有对私有字段的访问全部换成公开 API 之后,插件恢复正常。

这类问题没有银弹,唯一能给你的建议是:私有 API 在迁移时是最大的不确定因素,提前盘点项目里所有自定义插件,给自己的代码多留出半天缓冲时间。

6. 实测数据与场景化选型建议

最后用数据说话,我把三个不同项目的迁移前后对比列出来,给大家一个更直观的判断依据。

项目类型代码规模Vite 7 构建耗时Vite 8 构建耗时冷启动提升
中后台管理端约 12 万行业务代码41s12s9s 到 3s
组件库86 个组件24s6.5s5s 到 2s
文档站(SSR)约 300 个 MDX 页面32s9s6.5s 到 2.5s

可以看到收益是全场景的。组件库场景里,Rolldown 对多格式输出的支持明显更好,以前为了同时出 ESM、CJS、MJS 几种格式要做额外配置,现在基本零成本。SSR 项目里,服务端产物体积也小幅下降,服务启动时间跟着缩短。

至于"要不要升级",我的判断是:如果项目已经在用 Vite 7,且没有深度依赖 Rollup 私有 API 的插件,升级收益远大于风险,整个过程半天足够。如果还在 Vite 5 之前的老版本,建议先升到 7,熟悉一下 Environment API 的结构,再平滑过渡到 8。这一代改的东西确实多,一步跨三个版本,配置文件的改动面会大不少。

如果项目里还在用 webpack,并且体量不大,暂时没必要为了追新而迁移。Vite 8.0 的收益要在依赖多、构建链路复杂的项目里体现得最充分,小项目换过去体验差距不明显,反而要承担迁移成本。

我自己实际用了一个月之后的感受是:工具链升级只是起点,整个产线随之重新平衡的过程才是真正花时间的地方。升级完成后的那一周,我去看了 CI 流水线的耗时分布,发现 Vite 构建环节从 40 秒降到 12 秒之后,镜构建和产物压缩反而成了新的瓶颈。一开始我还怀疑是不是哪里配置出了问题,后来想明白是之前的流水线一直在等构建这个慢环节,现在构建快了,下游环节的相对占比自然就上来了。

所以最后分享一个小建议:升级之后别急着高兴,先把 CI 流水线每阶段的耗时记录拉出来看一圈,把优化重点放到真正占时间的那一步上。这次的迁移给我的体会是,换引擎解决的是最痛的那个点,但整个系统是联动的,后续还有很多地方值得跟着重新调一遍。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询