Vite 8 迁移实战指南:从 esbuild/Rollup 切换至 Rolldown + Oxc 工具链的完整拆解
本文基于 Vite 仓库官方的 Vite 8 迁移指南 编写,系统梳理从 Vite 7 升级到 Vite 8 的每一步变更:底层打包器由 esbuild + Rollup 全面替换为 Rolldown + Oxc 之后的配置迁移路径、自动兼容层的行为边界,以及 CJS 互操作性、压缩、模块类型检测等十余项破坏性变更。读完后,你可以判断自己项目命中的兼容性风险点,并逐项完成 esbuildOptions、esbuild、build.rollupOptions 等废弃配置的替换。
迁移背景:Vite 8 用了一套全新的工具链
Vite 8 最核心的变化是:构建与转换不再依赖 esbuild 和 Rollup,而是切换到 Rolldown 与 Oxc 生态。这直接带来三类影响:
- 配置层:一批
esbuild*、build.rollupOptions相关的配置项被废弃,但 Vite 保留了自动转换的兼容层,老配置仍可运行(会打印废弃警告); - 行为层:默认浏览器目标版本、CommonJS 互操作规则、
require外部模块的处理方式等发生了变化,部分代码可能需要适配; - 能力层:少数 Rollup 特性(如
system/amd输出格式、部分插件钩子)因 Rolldown 尚未支持而被移除。
仓库中的实现与这份文档严格对应,例如兼容转换逻辑位于 oxc 配置转换函数 和 依赖优化选项兼容层,构建默认值位于 build.ts。
另外有两类读者需要特别注意:
- 从
rolldown-vite(Rolldown 集成的技术预览版)迁移的用户:该包已经实现了 Rolldown 集成,因此本指南中标注 “NRV”(Not Relevant for Vite,对 rolldown-vite 用户不适用)的章节无需关注,只需阅读其余部分; - 从 Vite 6 迁移的用户:请先阅读 Vite 7 文档中的 v6 迁移指南完成 Vite 7 升级,再按本文完成 Vite 8 的变更。
默认浏览器目标版本上调
build.target 与 'baseline-widely-available' 的默认浏览器版本统一上调:
| 浏览器 | 旧默认值 | 新默认值 |
|---|---|---|
| Chrome | 107 | 111 |
| Edge | 107 | 111 |
| Firefox | 104 | 114 |
| Safari | 16.0 | 16.4 |
这些版本与 Baseline Widely Available 特性集在 2026-01-01 的基线对齐,即对应浏览器版本均已发布约两年半。如果你的项目需要覆盖更老的浏览器,请显式配置 build.target;反之,如果你的最低目标版本高于旧默认值,升级 Vite 8 后输出的语法可能更现代,体积或兼容性行为会有细微差异。
渐进式迁移:用 rolldown-vite 做中间站
rolldown-vite 包实现了 “Rolldown + Vite 7 其余行为不变” 的组合,可以作为从 Vite 7 到 Vite 8 的中间步骤:先在 Vite 7 上切换到 rolldown-vite(参考 Vite 7 文档的 Rolldown 集成指南),确认打包行为无回归后,再正式升级到 Vite 8。
对于已经从 rolldown-vite 迁移过来的用户,只需还原 package.json 中的依赖别名并升级到 Vite 8:
{
"devDependencies": {
"vite": "npm:rolldown-vite@7.2.2" // 旧
"vite": "^8.0.0" // 新
}
}
依赖预构建(Optimizer)改用 Rolldown
依赖优化器不再使用 esbuild,而是使用 Rolldown。Vite 仍支持 optimizeDeps.esbuildOptions 以保持向后兼容:它会被自动转换为 optimizeDeps.rolldownOptions,但该选项已废弃,未来会移除。
自动转换的选项映射如下(详见 依赖优化配置参考):
| esbuildOptions | rolldownOptions |
|---|---|
minify |
output.minify |
treeShaking |
treeshake |
define |
transform.define |
loader |
moduleTypes |
preserveSymlinks |
!resolve.symlinks(注意取反) |
resolveExtensions |
resolve.extensions |
mainFields |
resolve.mainFields |
conditions |
resolve.conditionNames |
keepNames |
output.keepNames |
platform |
platform |
plugins |
plugins(部分支持) |
从源码可以确认这一兼容层的行为边界:config.ts 中的转换逻辑 在检测到 optimizeDeps.esbuildOptions 非空时会先打印废弃警告,然后按 “仅在对应 rolldownOptions 字段未显式设置时” 逐一填充;loader 的转换会跳过 copy、css、default、file、local-css 这些无法映射的取值。源码注释还明确列出了一批不会被转换的选项(legalComments、target、supported、jsx* 系列、mangleProps 等),这意味着如果这些选项曾在依赖优化中生效,需要手动确认新的等效配置。
你可以在 configResolved 钩子中查看兼容层最终设置的选项,验证转换结果:
const plugin = {
name: 'log-config',
configResolved(config) {
console.log('options', config.optimizeDeps.rolldownOptions)
},
}
建议尽快将配置迁移到 optimizeDeps.rolldownOptions。
JavaScript 转换:Oxc 接管 esbuild transform
JavaScript 转换(TypeScript/JSX 编译)由 Oxc 完成。esbuild 配置项同样保留兼容层,会被自动转换为 oxc 配置。esbuild 选项已废弃,未来会移除。
自动转换的映射关系:
esbuild.jsxInject->oxc.jsxInjectesbuild.include->oxc.includeesbuild.exclude->oxc.excludeesbuild.jsx->oxc.jsx:'preserve'->'preserve''automatic'->{ runtime: 'automatic' },其中esbuild.jsxImportSource->oxc.jsx.importSource'transform'->{ runtime: 'classic' },其中esbuild.jsxFactory->oxc.jsx.pragma、esbuild.jsxFragment->oxc.jsx.pragmaFrag
esbuild.jsxDev->oxc.jsx.developmentesbuild.jsxSideEffects->oxc.jsx.pureesbuild.define->oxc.defineesbuild.banner/esbuild.footer-> 需改用自定义插件的 transform 钩子实现
这个转换在仓库中的实现是 convertEsbuildConfigToOxcConfig:jsx 三种取值分别映射到 Oxc 的 runtime 模式,jsxSideEffects 取反后写入 pure,而 banner/footer 会打印“该选项已废弃,请用带 transform 钩子的插件替代”的警告(对应 esbuildBannerFooterCompatPlugin 的兼容实现)。新配置项的用法可参考 oxc 配置参考。
两个需要注意的转换限制
esbuild.supported不受 Oxc 支持。该选项用于控制 esbuild 是否降级某些浏览器原生特性;从源码结构看,Oxc 转换路径中没有对应能力,如果你的项目依赖它做了低版本浏览器降级,需要单独评估替代方案。- Oxc Transformer 暂不支持原生装饰器(native decorators)降级,正在等待规范进展。如果项目使用了需要在旧环境中降级的原生装饰器,官方文档给出了两套临时方案:
方案一:Babel
# npm / yarn / pnpm / bun 等价:
npm install -D @rolldown/plugin-babel @babel/plugin-proposal-decorators
// vite.config.ts
import { defineConfig } from 'vite'
import babel from '@rolldown/plugin-babel'
function decoratorPreset(options: Record<string, unknown>) {
return {
preset: () => ({
plugins: [['@babel/plugin-proposal-decorators', options]],
}),
rolldown: {
// 仅当文件包含装饰器时才运行该转换
filter: {
code: '@',
},
},
}
}
export default defineConfig({
plugins: [babel({ presets: [decoratorPreset({ version: '2023-11' })] })],
})
方案二:SWC
npm install -D @rollup/plugin-swc @swc/core
import { defineConfig, withFilter } from 'vite'
import swc from '@rollup/plugin-swc'
export default defineConfig({
// ...
plugins: [
withFilter(
swc({
swc: {
jsc: {
parser: { decorators: true, decoratorsBeforeExport: true },
transform: { decoratorVersion: '2023-11' },
},
},
}),
// 仅当文件包含装饰器时才运行该转换
{ transform: { code: '@' } },
),
],
})
esbuild 降级为可选依赖
Vite 8 中 esbuild 不再被直接使用,降级为可选依赖。如果你的插件使用了 transformWithEsbuild 函数,需要自己将 esbuild 安装为 devDependency;且 transformWithEsbuild 已废弃,推荐迁移到新的 transformWithOxc。后者的实现位于 transformWithOxc 函数,基于 rolldown/utils 的 transformSync 完成转换并附带 source map 与 tsconfig 解析缓存。
你可以通过 configResolved 查看兼容层写入的 oxc 选项:
const plugin = {
name: 'log-config',
configResolved(config) {
console.log('options', config.oxc)
},
}
JavaScript 压缩:Oxc Minifier 成为默认
JavaScript 压缩默认由 Oxc Minifier 完成。在 build.ts 中可以看到客户端构建的默认值:minify 为 true 时解析为 'oxc',服务端与 bundler 模式开发下则关闭压缩。
迁移要点:
- 回退到 esbuild:设置废弃选项
build.minify: 'esbuild'可切回 esbuild 压缩,此时构建阶段会额外挂载 esbuild 插件(见 build.ts 中 minify 为 esbuild 时的 post 插件),并且必须自行安装esbuild为devDependency,因为 Vite 已不直接依赖 esbuild。 - 选项迁移:原来用
esbuild.minify*系列控制压缩行为的,改用build.rolldownOptions.output.minify;原来用esbuild.drop删除console/debugger的,改用 Oxc Minifier 的output.minify.compress.drop*系列选项。 - 属性混淆(mangling)不支持:
mangleProps、reserveProps、mangleQuoted、mangleCache在 Oxc 中没有对应能力;如有需求,可关注 Oxc 项目的对应 issue 进展。 - 压缩假设差异:esbuild 与 Oxc Minifier 对源码的假设略有不同,若怀疑压缩导致线上问题,建议对照两者的 minify assumptions 文档逐一排查,并向上游报告与压缩相关的缺陷。
CSS 压缩:Lightning CSS 成为默认
CSS 压缩默认改用 Lightning CSS。在 build.ts 中的默认值逻辑 可以看到:服务端环境固定使用 'lightningcss',客户端环境在 build.minify 开启时跟随启用。
- 回退到 esbuild:设置
build.cssMinify: 'esbuild',同样需要自行安装esbuild为devDependency。 - 体积影响:Lightning CSS 支持更好的语法降级(syntax lowering),CSS 包体积可能略微增大,这是功能增强带来的正常现象,升级后可对比构建产物体积确认影响范围。
CommonJS 互操作性:default 导入规则统一
这是升级 Vite 8 时最容易踩坑的行为变更。从 CommonJS 模块的 default 导入现在按统一规则处理:满足以下任一条件时,default 即被导入 CJS 模块的 module.exports 值;否则取 module.exports.default:
- 导入方(importer)是
.mjs或.mts文件; - 导入方最近的
package.json的type字段为module; - 被导入 CJS 模块的
module.exports.__esModule未设置为true。
旧行为对照
变更前,开发与构建两套逻辑并不一致:
- 开发环境旧规则:导入方被依赖优化且为
.mjs/.mts,或导入方被依赖优化且其最近package.json的type为module,或__esModule不为true时,取module.exports;否则取module.exports.default; - 构建旧规则(Rollup commonjs 插件
defaultIsModuleExports为默认'auto'时):__esModule不为true,或module.exports上不存在default属性时,取module.exports;否则取module.exports.default。
可以看到新规则消除了 “构建时靠 default 属性是否存在兜底” 的模糊分支,开发和构建行为一致。这个变更可能破坏依赖旧规则的 CJS 包导入。仓库中保留了回退开关:legacy 配置类型定义 中的 inconsistentCjsInterop,其 JSDoc 明确说明它用于 “opt-in 到 Vite 8 之前不一致的 CJS 互操作行为”,并在 importAnalysis 插件 中参与开发期的互操作判定,同时经 插件索引 传递给构建侧。
如果某个三方包因该变更出问题,官方建议是向该包作者反馈或提交 PR(并附上 Rolldown 关于 CJS 打包的文档背景),而不是长期依赖回退开关:
export default defineConfig({
legacy: {
inconsistentCjsInterop: true, // 临时恢复旧行为
},
})
模块解析与外部模块行为变更
移除基于格式嗅探的模块解析
过去当 package.json 同时存在 browser 和 module 字段时,Vite 会根据文件内容嗅探格式、为浏览器挑选 ESM 文件。这个启发式源于部分包用 module 指向 Node 侧 ESM、用 browser 指向 UMD 的历史包袱。如今标准的 exports 字段已广泛采用,Vite 8 移除了该启发式,始终按 resolve.mainFields 的字段顺序解析。
如果项目依赖了旧行为,两种替代方案:用 resolve.alias 把目标字段映射到期望的文件,或用包管理器的补丁机制(如 patch-package、pnpm patch)修改该包的 package.json。
外部化模块的 require 调用保持原样
对外部化模块的 require 调用现在保留为 require 调用,不再转换为 import 语句,以保留 require 的语义。若你确实希望转换,可使用 Rolldown 内置的 esmExternalRequirePlugin,它从 vite 直接再导出(见 node/index.ts):
import { defineConfig, esmExternalRequirePlugin } from 'vite'
export default defineConfig({
// ...
plugins: [
esmExternalRequirePlugin({
external: ['react', 'vue', /^node:/],
}),
],
})
UMD / IIFE 输出中 import.meta.url 不再填充
import.meta.url 在 UMD / IIFE 输出格式中不再被 polyfill,默认被替换为 undefined。如需恢复旧行为,可以组合 define 选项与 build.rolldownOptions.output.intro 来实现。
移除 build.rollupOptions.watch.chokidar
该选项已删除,请迁移到 build.rolldownOptions.watch.watcher。
manualChunks 对象形式移除、函数形式废弃
对象形式的 output.manualChunks 不再支持;函数形式已废弃。Rolldown 提供了更灵活的 codeSplitting 选项替代,详见 Rolldown 的 Manual Code Splitting 文档。
build() 抛出 BundleError
此变更仅影响 JS API 用户。
通过 build() 调用构建时,抛出的不再是插件内原始错误,而是 BundleError,其类型为 Error & { errors?: RolldownError[] },单个错误包裹在 errors 数组中。需要遍历具体错误时访问 .errors:
try {
await build()
} catch (e) {
if (e.errors) {
for (const error of e.errors) {
console.log(error.code) // 错误码
}
}
}
模块类型自动检测(影响插件作者)
Rolldown 支持按解析到的 id 扩展名自动设置模块类型(module types,类似 esbuild 的 loader 选项)。如果你在 load 或 transform 钩子中把其他模块类型的内容转换成 JavaScript,可能需要在返回值中显式加上 moduleType: 'js':
const plugin = {
name: 'txt-loader',
load(id) {
if (id.endsWith('.txt')) {
const content = fs.readFile(id, 'utf-8')
return {
code: `export default ${JSON.stringify(content)}`,
moduleType: 'js', // 需要显式声明
}
}
},
}
Vite 自身的 Oxc 插件就遵循这一约定:oxc 插件的 transform 返回值 中显式携带 moduleType: 'js'。
其他相关废弃项
以下选项已废弃,未来会移除:
build.rollupOptions:更名为build.rolldownOptions(在 build.ts 中可见rollupOptions标记为@deprecated的别名);worker.rollupOptions:更名为worker.rolldownOptions;build.commonjsOptions:现为 no-op(空操作);build.dynamicImportVarsOptions.warnOnError:现为 no-op;resolve.alias[].customResolver:请改用带resolveId钩子且enforce: 'pre'的自定义插件替代。
已移除的废弃特性
- 向
import.meta.hot.accept传递 URL 不再受支持,请改为传递模块 id。
进阶:少数场景会受影响的破坏性变更
以下变更预计只影响少数使用场景,按需核对:
- Extglobs 不支持:picomatch 的 extglobs 语法在依赖优化等 glob 匹配场景暂不支持;
- TypeScript 传统 namespace 仅部分支持:需对照 Oxc Transformer 的 TypeScript 文档确认你的用法是否在支持范围内;
- define 不再共享对象引用:向
define传入对象值时,每个被替换的变量会持有对象的独立副本(Oxc 的 define 行为),依赖“多处引用同一对象”的逻辑会失效; - bundle 对象行为变化(传入
generateBundle/writeBundle钩子、由build返回的对象):- 不支持
bundle[foo] = ...赋值,请用this.emitFile()代替(Rollup 本身也不推荐赋值); - 各钩子间共享的不再是同一引用;
structuredClone(bundle)会抛出DataCloneError,需改为structuredClone({ ...bundle });
- 不支持
- Rollup 的 parallel 钩子均按顺序执行:依赖钩子并行执行的插件行为会变慢或顺序敏感;
"use strict";注入策略不同:某些情况下不再注入,需对照 Rolldown 的 directives 文档评估;- plugin-legacy 不支持降级到 ES5 及以下:Vite 仓库内置的 plugin-legacy 包 在此约束下工作,需要 ES5 输出的老项目需另寻方案;
build.target传入同一浏览器的多个版本会报错:esbuild 会静默选取最新版本,Vite 8 选择直接报错提示意图不清;- Rolldown 尚未支持、Vite 也随之移除的特性:
build.rollupOptions.output.format: 'system'build.rollupOptions.output.format: 'amd'shouldTransformCachedModule钩子resolveImportMeta钩子renderDynamicImport钩子resolveFileUrl钩子
parseAst/parseAstAsync废弃:改用功能更完整的parseSync/parse。仓库中 node/index.ts 可见parseAst、parseAstAsync均标记@deprecated并指向parseSync;- 注释移除时机变化:注释现在在
renderChunk钩子之前被移除(Rollup 是在之后);且除 RolldownOutputOptions.comments所列之外的注释会被移动,而 Rollup 只在相邻代码被移除时才删除注释——依赖注释存在的插件(如版权头处理)需要适配。
迁移落地清单
结合上述内容,一份可执行的升级检查单如下:
- 确认起点:在 Vite 6 上先完成 Vite 7 升级;在 Vite 7 上可先切
rolldown-vite过渡; - 检查
build.target:默认浏览器目标已上调(Chrome/Edge 111、Firefox 114、Safari 16.4),需要覆盖旧浏览器时显式指定; - 替换废弃配置:
optimizeDeps.esbuildOptions→optimizeDeps.rolldownOptions,esbuild→oxc,build.rollupOptions/worker.rollupOptions→*.rolldownOptions;用configResolved钩子打印最终选项验证兼容层转换结果; - 审计 CJS 依赖:重点验证从 CJS 包做
default导入的代码路径,必要时临时开启legacy.inconsistentCjsInterop: true,并向包作者反馈; - 确认压缩配置:JS 默认 Oxc Minifier、CSS 默认 Lightning CSS;若需回退 esbuild,安装 esbuild 为 devDependency 并设置
build.minify: 'esbuild'/build.cssMinify: 'esbuild'; - 排查特殊场景:
banner/footer、装饰器降级、system/amd格式、manualChunks对象形式、import.meta.hot.accept传 URL、parseAst调用、依赖钩子并行执行的插件; - 清理兼容开关:迁移稳定后移除
legacy.inconsistentCjsInterop等临时开关,回归 Rolldown 的标准行为。
以上所有行为均以当前仓库实现为准:配置兼容层见 config.ts 与 oxc.ts,构建默认值与回退插件挂载见 build.ts,导出面变更见 node/index.ts。升级后如遇与压缩、CJS 互操作相关的回归,建议优先对照 Rolldown 与 Oxc 官方文档中的 assumptions 说明定位差异来源。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0626
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00