代码 Vite 8 升级笔记:Rolldown + Oxc 替换后真正会出问题的几处

2026-10-19 21:01:58

Vite 8 升级笔记:Rolldown + Oxc 替换后真正会出问题的几处

Vite 8(2026-03-12)把打包器从 Rollup 换成了 Rolldown,把转换器从 esbuild 换成了 Oxc。插件接口层面基本兼容,但有几处语义发生了根本变化:CJS default 导入规则、对象形式 manualChunks、esbuild 变成可选依赖、UMD/IIFE 里的 import.meta.url、默认浏览器目标,以及 import.meta.hot.accept 签名。下面按升级时容易出问题的顺序记录。

  • 迁移指南:https://vite.dev/guide/migration
  • 发布公告:https://vite.dev/blog/announcing-vite8

分两步升级:先换 rolldown-vite,再升到 8

rolldown-vite 这个包就是用 Rolldown 实现的 Vite 7。先在现有 Vite 7 项目里把打包器换掉,跑通插件链、比对构建产物,再升到 8。项目大时官方也推荐两步走,避免一次同时改版本号和底层实现,出问题不好定位。

配置项改名

顶层配置中的 rollupOptions 统一改成 rolldownOptions,esbuild 换成 oxc。旧名暂时还能用,但已经标记弃用。

// vite.config.js
export default {
  build: {
    // 旧:rollupOptions
    // 新:rolldownOptions
    rolldownOptions: {
      output: {
        // 对象形式的 manualChunks 已被删除,见下文
        manualChunks(id) {
          if (id.includes('node_modules')) return 'vendor'
        },
      },
    },
  },
  worker: {
    // worker.rollupOptions -> worker.rolldownOptions
    rolldownOptions: {},
  },
  // 旧:esbuild
  // 新:oxc
  oxc: {
    jsxInject: `import React from 'react'`,
  },
}

依赖预构建走 Rolldown,optimizeDeps.esbuildOptions 已弃用,会自动转换为 optimizeDeps.rolldownOptions:

// optimizeDeps.esbuildOptions -> optimizeDeps.rolldownOptions
{
  minify: true,        // -> rolldownOptions.output.minify
  treeShaking: true,   // -> treeshake
  define: {},          // -> transform.define
  loader: {},          // -> moduleTypes
  preserveSymlinks,    // -> !resolve.symlinks
  resolveExtensions,   // -> resolve.extensions
  mainFields,
  conditions,          // -> conditionNames
  keepNames,
  platform,
  plugins,             // 部分支持
}

JS 转换的 esbuild 选项同样会自动映射到 oxc:

// esbuild -> oxc
{
  jsxInject,        // -> oxc.jsxInject
  include, exclude, // 支持
  jsx,              // 'preserve' | 'automatic' -> oxc.jsx: { runtime: 'automatic' }
  jsxImportSource,  // -> oxc.jsx.importSource
  jsxFactory,       // -> oxc.jsx.pragma
  jsxFragment,      // -> oxc.jsx.pragmaFrag
  jsxDev,           // -> oxc.jsx.development
  jsxSideEffects,   // -> oxc.jsx.pure
  define,           // -> oxc.define
}
// esbuild.supported Oxc 不支持

另外,Oxc 转换器目前还不支持把原生装饰器降级,需要走 Babel 或 SWC。

CJS default 导入语义变严

这是最容易在运行时静默出错的一处。从 CJS 模块默认导入时,只有满足下面任一条件,default 才等于 module.exports:

  • 导入方是 .mjs / .mts;
  • 最近的 package.json 里 type: "module";
  • module.exports.__esModule !== true。

否则 default 取 module.exports.default。以前 dev 和 build 两套行为不一致,现在统一成一套,因此有些以前能跑的代码会取到 undefined。想恢复旧行为,可以设 legacy.inconsistentCjsInterop: true。

对象形式的 manualChunks 被删除

output.manualChunks 的对象形式已经移除,函数形式也已弃用,改为使用 Rolldown 的 codeSplitting 选项。上面配置块里保留的是函数写法,但如果项目里靠对象映射分包,必须改写。

esbuild 变成可选依赖

Vite 自身不再直接依赖 esbuild,它只是可选的。之前依赖 transformWithEsbuild 的插件会直接报错找不到模块,需要在项目里把 esbuild 装回 devDependency;同时 transformWithEsbuild 已弃用,改用 transformWithOxc。

压缩同理:JS 压缩换了 Oxc minifier,build.minify: 'esbuild' 仍可回退,但前提是装了 esbuild。esbuild.minify* 系列选项迁到 build.rolldownOptions.output.minify,esbuild.drop 迁到 output.minify.compress.drop*。属性名混淆(mangleProps 等)Oxc 不支持。

CSS 压缩默认换成 Lightning CSS,可用 build.cssMinify: 'esbuild' 回退,产物体积可能会略微增加。

UMD / IIFE 里的 import.meta.url 变 undefined

import.meta.url 不再在 UMD 和 IIFE 产物中做 polyfill,默认被替换成 undefined。依赖这个值的库在非 ESM 构建下会出错,需要用 define 配合 build.rolldownOptions.output.intro 手动补回去。

默认浏览器目标抬高

build.target 的默认基线更新为 2026-01-01 的 Baseline Widely Available:Chrome 107 → 111,Edge 107 → 111,Firefox 104 → 114,Safari 16.0 → 16.4。老浏览器需要显式配 build.target。注意现在给 build.target 传同一个浏览器的多个版本会直接报错。

import.meta.hot.accept 不再接受 URL

import.meta.hot.accept 带 URL 参数的写法已移除(#21382),HMR 边界要改成传模块依赖本身。

其他会影响构建结果的改动

  • 模块解析不再做 format sniffing:browser 和 module 字段同时存在时,以前 Vite 会读文件内容,给浏览器挑 ESM 版本,现在严格按 resolve.mainFields 的顺序。需要用 resolve.alias 或 patch-package 兜底。
  • externalized 模块的 require 原样保留:不再自动转成 import。要转就用 esmExternalRequirePlugin,它从 vite 里重新导出。
  • watch 配置:build.rollupOptions.watch.chokidar 移除,换成 build.rolldownOptions.watch.watcher。
  • JS API 错误类型:build() 抛 BundleError,不再抛原始错误,调用方需要改 catch 逻辑。
  • 插件作者注意:模块类型自动检测的变化可能要求你在 load / transform 的返回值里显式给出 moduleType: 'js'。
  • 转为 no-op 或移除的项:build.commonjsOptions 变 no-op,build.dynamicImportVarsOptions.warnOnError 变 no-op,resolve.alias[].customResolver 移除。

边界情况

extglob 暂不支持;TS 的 legacy namespace 只部分支持;define 对对象不共享引用;bundle 对象上不能给 bundle[foo] 赋值,hook 之间也不共享引用,structuredClone(bundle) 会抛 DataCloneError,需要写成 structuredClone({...bundle});原本并行的 hook 变成串行;"use strict" 有时不会被注入;plugin-legacy 的 ES5 目标不支持;'system' / 'amd' 输出格式不再支持;shouldTransformCachedModule、resolveImportMeta、renderDynamicImport、resolveFileUrl 这几个 hook 不支持;parseAst 弃用,改用 parseSync / parse。

官方公告给出的构建提速数字最高到 10–30 倍,插件兼容性按完全兼容处理。实际升级时,上面这些语义变化比性能数字更值得先过一遍。

复制全文 生成海报 Vite 前端构建 Rolldown 前端工程化

推荐文章

程序员茄子在线接单