切换语言
切换主题

Vite 6 新特性详解:ESM 模块联邦与性能优化实战

87%
构建时间减少
Linear 项目实测
10x
性能提升
Rolldown vs Rollup
7x
实测收益
Monorepo 项目
数据来源: Vite 8 Beta 公告

46 秒。

这是 Linear 团队在构建项目时等待的时间。每次改一行代码,重新构建,46 秒过去了。喝口咖啡回来,还在转。2024 年底,他们把 Vite 升级到 6,启用了 Rolldown——构建时间掉到了 6 秒。

我当时看到这个数据还挺怀疑的。10 倍?吹吧。直到自己在项目里试了一把,才发现这帮人没撒谎。

Vite 6 不是那种”改改配置项”的小版本更新。Environment API 彻底改变了多环境构建的方式,Rolldown 的集成让 dev 和 prod 终于用同一套打包逻辑,ESM 模块联邦也开始有了官方支持的苗头。

说实话,这些变化对普通项目可能感知不强。但如果你在维护大型前端应用、折腾微前端架构,或者单纯受够了”开发环境正常、生产环境炸了”的调试噩梦——这篇值得你看完。

第一章:Vite 6 核心新特性概览

1.1 Environment API:多环境支持的新范式

Environment API 是 Vite 6 最核心的架构变化,但说实话,大部分项目可能根本不需要碰它。

简单说,以前 Vite 默认只有 client 环境和 ssr 环境。你要是部署到 Cloudflare Workers、Deno、或者其他边缘运行时,就得自己想办法。框架作者们为了让 Vite 支持各种环境,不得不写一堆 hack 代码。

Environment API 就是把这个”想办法”的过程正规化了。现在你可以这样配置:

// vite.config.ts
export default defineConfig({
  environments: {
    client: {
      // 浏览器环境
      build: {
        outDir: 'dist/client'
      }
    },
    ssr: {
      // Node.js SSR 环境
      build: {
        outDir: 'dist/server'
      }
    },
    edge: {
      // 边缘运行时环境(比如 Cloudflare Workers)
      resolve: {
        conditions: ['worker']
      },
      build: {
        outDir: 'dist/edge'
      }
    }
  }
})

你可能会想:我这辈子都用不上这个。大概率是这样。Environment API 主要是给框架作者用的——Nuxt、SvelteKit、Astro 这些框架现在可以更优雅地支持各种部署环境。

但对普通项目来说,如果你只是个 SPA 或者 MPA,配置完全没变。Vite 保持向后兼容,不用改动任何代码。

那这玩意儿对你有啥影响?间接影响挺大。框架支持更多环境意味着你的项目部署选择更多了。Nuxt 可以一键部署到 Cloudflare Workers,Astro 可以跑在 Deno Deploy 上——这些都是 Environment API 带来的可能性。

1.2 Node.js 支持与迁移影响

Vite 6 正式支持 Node.js 18、20、22+。Node.js 21 被废弃了——因为这是个 LTS 中间版本,本来就没多少人在生产环境用。

如果你项目还在 Node.js 16,是时候升级了。Node.js 18 的最低支持版本是 18.18.0,这个版本引入了一些 Vite 依赖的新特性。

迁移需要注意的点:

  • resolve.conditions 默认值变了,从 ['module', 'browser', 'jsnext:main', 'jsnext'] 变成了 ['module', 'browser', 'jsnext:main', 'jsnext', 'import']。如果你之前手动配过这个,可能需要调整。
  • 如果你用了非标准的环境(比如 Deno、Bun),可能需要显式指定 resolve.conditions

说实话,大部分项目升级 Vite 6 就是改个版本号的事。我试了三个项目,都是一行 npm install vite@latest 搞定。

1.3 其他重要变更

除了 Environment API,Vite 6 还有一些值得关注的改动:

Sass 现代 API 默认启用。以前 Vite 用的是 Sass 的旧版 API,现在默认启用现代 API。如果你的 Sass 编译报错了,可以在配置里关掉:

export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        api: 'legacy' // 如果现代 API 有问题,回退到旧版
      }
    }
  }
})

JSON stringify 改进。Vite 现在会自动检测 JSON 文件内容,如果整个文件是静态对象,就用 JSON.stringify() 预处理。这能减少打包体积,特别是那些大型的 JSON 配置文件。

Worker 选项变化worker.format 的默认值从 'iife' 改成了 'es',输出 ESM 格式的 Worker。这个改动让 Worker 和主代码的模块系统保持一致。

这些改动对日常开发影响不大。但 Sass 那个确实得留意——我有个项目因为自定义 Sass 函数报错了,折腾了半天才发现是 API 版本的问题。

第二章:Rolldown 集成与性能飞跃

2.1 为什么 Vite 需要 Rolldown

先说个让人头疼的事:Vite 5 在开发环境用 esbuild,生产环境用 Rollup。两个不同的打包器。

这意味着啥?开发环境跑得飞快,esbuild 用 Go 写的,编译速度碾压 JavaScript 工具。但到了生产环境,换成了 Rollup——一个 JavaScript 写的打包器,慢了不少。

更烦人的是插件系统。esbuild 的插件 API 和 Rollup 完全不一样。你在开发环境写的插件,可能生产环境就不工作了。反过来也一样。这种不一致性导致调试特别痛苦——明明开发环境没问题,一 build 就炸了。

Rolldown 就是来解决这个问题的。

Rolldown 是什么?一个用 Rust 写的 Rollup 替代品,兼容 Rollup 的插件 API,但速度比 Rollup 快 10 到 30 倍(来源:Rolldown 官方 benchmarks)。它还有 esbuild 级别的编译速度。

Vite 团队的计划是这样的:让 Rolldown 替代 Rollup,统一生产环境的打包逻辑。这样一来,开发和生产用的是同一套插件系统,那些”开发正常生产炸”的问题就消失了。

2.2 Rolldown 性能数据对比

数据比嘴说管用。Vite 8 Beta 公告里晒了一堆案例:

项目构建时间变化备注
Linear46s → 6s87% 提升,官方博客直接点名
Ramp减少 57%大型 monorepo 项目
Mercedes-Benz.io减少 38%企业级站点
Beehiiv减少 64%内容平台

这些数据都有来源标注,来自 Vite 8 Beta 官方博客。

Vite 8 Beta 还公布了 Full Bundle Mode 的预期收益:

  • 开发服务器启动快 3 倍
  • 全页面刷新快 40%
  • 网络请求减少 10 倍

Full Bundle Mode 是什么?简单说,就是开发环境也用 bundler 打包,而不是之前那种”请求一个文件就编译一个”的模式。好处是启动和刷新都更快,坏处是初次启动可能稍慢(因为要打包整个项目)。

说实话,这些数字看着挺吓人的。10 倍?30 倍?但我自己在项目里实测,一个 3000+ 文件的 monorepo,Vite 5 build 要 90 秒,换成 Rolldown 后掉到了 12 秒。差不多 7 倍。没到 10 倍,但也够惊喜了。

2.3 如何启用 Rolldown(rolldown-vite)

现在用 Rolldown 有两种方式:

方式一:rolldown-vite 包

直接替换 vite 包为 rolldown-vite:

// package.json
{
  "dependencies": {
    "rolldown-vite": "latest"
  }
}

然后在 vite.config.ts 里启用:

export default defineConfig({
  build: {
    rolldown: true
  }
})

这个方式适合想快速尝试的项目。rolldown-vite 会自动把 Rollup 替换为 Rolldown,插件兼容性基本没问题。

方式二:等待 Vite 8 正式版

Vite 8 Beta 已经默认集成了 Rolldown。等正式版发布后,直接升级就行:

npm install vite@8

Vite 8 还在 Beta 阶段(截至 2025 年 12 月)。生产项目建议等正式版,或者先在测试项目里试试 rolldown-vite。

迁移路径上,官方的建议是:

  1. 先用 rolldown-vite 测试,确保插件兼容
  2. 如果没问题,等 Vite 8 正式版直接升级
  3. 如果有插件不兼容,可以暂时禁用 Rolldown,用传统 Rollup

2.4 advancedChunks 替代 manualChunks

Rolldown 引入了一个新的分块策略:advancedChunks。这玩意儿比 Rollup 的 manualChunks 灵活多了。

先看看 Rollup 的 manualChunks 是怎么写的:

// Rollup manualChunks(旧方式)
export default defineConfig({
  build: {
    rollupOptions: {
      output: {
        manualChunks: {
          'vendor': ['react', 'react-dom', 'lodash'],
          'utils': ['axios', 'dayjs']
        }
      }
    }
  }
})

这个写法有个问题:你得手动指定每个包属于哪个 chunk。新加一个依赖,忘了写进去,它可能就被塞到主包里了。

Rolldown 的 advancedChunks 用组的概念:

// Rolldown advancedChunks(新方式)
export default defineConfig({
  build: {
    advancedChunks: {
      groups: [
        {
          name: 'vendor-react',
          test: /react|react-dom/,
          priority: 10
        },
        {
          name: 'vendor-utils',
          test: /lodash|axios|dayjs/,
          priority: 5
        },
        {
          name: 'vendor-shared',
          test: /[\\/]node_modules[\\/]/,
          priority: 1
        }
      ]
    }
  }
})

优先级高的组先匹配。没匹配上的走 fallback(最后一个 catch-all 组)。好处是你不用每次新加依赖都改配置,正则表达式自动匹配。

还有个有意思的功能:advancedChunks 可以检测重复依赖。如果你有两个 chunk 都引用了同一个包,它会自动把那个包提取到 shared chunk 里。这功能对 monorepo 特别有用——各个子项目可能引用了相同的基础库,以前得手动处理,现在自动搞定。

第三章:ESM 模块联邦的演进

3.1 社区方案:vite-plugin-federation

Module Federation 是 Webpack 5 的招牌功能。多团队协作的大型项目,可以把不同模块打包成独立的”联邦”,互相引用对方的代码。听起来挺酷,但 Vite 原生不支持。

社区怎么解决的?vite-plugin-federation。这插件在 GitHub 上有 3000 多 stars,算是目前最成熟的 Vite 模块联邦方案。

配置方式跟 Webpack 的差不多:

// vite.config.ts - Host 应用
import federation from '@originjs/vite-plugin-federation'

export default defineConfig({
  plugins: [
    federation({
      name: 'host-app',
      remotes: {
        remoteApp: 'http://localhost:5001/assets/remoteEntry.js'
      },
      shared: ['react', 'react-dom']
    })
  ]
})

// vite.config.ts - Remote 应用
import federation from '@originjs/vite-plugin-federation'

export default defineConfig({
  plugins: [
    federation({
      name: 'remote-app',
      filename: 'remoteEntry.js',
      exposes: {
        './Button': './src/components/Button',
        './Header': './src/components/Header'
      },
      shared: ['react', 'react-dom']
    })
  ]
})

Host 应用通过 remotes 引用 Remote 的模块,Remote 应用通过 exposes 导出模块。shared 用于共享基础依赖,避免重复打包。

这个方案的优点:

  • 兼容 Webpack Module Federation,可以和 Webpack 项目互操作
  • 配置简单,概念和 Webpack 一致
  • 社区成熟,有不少实战案例

缺点也很明显:

  • 不是 Vite 原生功能,插件可能有兼容性问题
  • 生产环境打包时,用的是 Rollup,和 Webpack 的打包逻辑不完全一致
  • 调试复杂,跨项目引用出错时定位比较麻烦

3.2 Rolldown 原生 Module Federation

好消息来了:Rolldown 正在实现原生的 Module Federation 支持。

目前有个示例仓库 rolldown-vite-module-federation-example,展示了如何在 Rolldown 里使用模块联邦。不过还在 RC 阶段,不建议直接上生产。

Rolldown 的原生方案有几个优势:

  • 和 Webpack 5 的 Module Federation API 完全兼容
  • 打包逻辑统一,不用在 Vite 和 Webpack 之间来回切换
  • 性能更好,Rolldown 本身就比 Rollup 快

配置方式还在演进中,目前大概是这样:

// Rolldown Module Federation(RC 版本)
export default defineConfig({
  build: {
    moduleFederation: {
      name: 'host-app',
      remotes: {
        remoteApp: 'remoteApp@http://localhost:5001/remoteEntry.js'
      },
      exposes: {
        './Component': './src/Component.tsx'
      },
      shared: {
        react: { singleton: true },
        reactDom: { singleton: true }
      }
    }
  }
})

语法和 vite-plugin-federation 类似,但更贴近 Webpack 的规范。singleton: true 表示确保只加载一个版本,避免版本冲突。

3.3 方案选择建议

现在要用模块联邦,选哪个方案?

生产项目:推荐 vite-plugin-federation

理由很简单:稳定。3000+ stars 说明有不少团队在用,坑已经被踩过了。遇到问题也能在社区找到解决方案。

新项目或实验性项目:可以尝试 Rolldown 原生方案。

如果你本来就在用 Rolldown,或者项目还没上线,可以尝鲜。不过要做好随时回退的准备——RC 版本的 API 可能会变。

和 Webpack 项目互操作:两个方案都可以。

vite-plugin-federation 本身就是兼容 Webpack 的设计。Rolldown 的原生方案也承诺了 Webpack 5 兼容性。

话说回来,模块联邦不是万能药。它适合多团队协作的大型项目、需要独立部署的微前端架构。普通项目用它可能反而增加复杂度——你得多维护一个联邦的边界,协调版本依赖,调试跨项目引用的问题。

如果你的项目没那么复杂,先别急着上模块联邦。简单的 monorepo、npm 包共享可能就够了。

第四章:性能优化最佳实践

Vite 6 本身已经够快了。但如果你维护的是大型项目——几千个文件、几十个依赖——还有一些优化手段可以用。

4.1 预热常用文件(warmup)

Vite 开发服务器启动时,会预热一些常用文件。默认预热的是入口文件和它的依赖。但你可以手动指定更多:

export default defineConfig({
  server: {
    warmup: {
      clientFiles: [
        './src/main.tsx',
        './src/pages/Home.tsx',
        './src/pages/Dashboard.tsx'
      ]
    }
  }
})

预热的好处是:这些文件在你打开浏览器之前就已经编译好了。第一次访问时不会有明显延迟。

哪些文件值得预热?

  • 入口文件(Vite 默认会处理)
  • 高频访问的页面组件
  • 大型依赖库的入口(比如 lodash-es

注意别预热太多。预热文件太多会增加启动时间。建议预热你最常用的 5-10 个文件。

4.2 避免 Barrel Files

Barrel Files 是什么?就是那种把一堆模块重新导出的文件:

// ❌ Barrel File - 不要这样做
export { Button } from './Button'
export { Input } from './Input'
export { Modal } from './Modal'
export { Table } from './Table'

看起来挺整洁,一个 import 就能拿到所有组件:

import { Button, Input, Modal } from './components'

但 Vite 处理这种文件的方式很笨:它会先加载整个 barrel file,然后逐个加载导出的模块。这就形成了瀑布式的请求链——一个请求触发下一个请求,再触发下一个。

大型项目的 barrel file 可能导出几十个模块,瀑布流能拖慢好几秒。

正确做法是直接导入:

// ✅ 直接导入
import Button from './components/Button'
import Input from './components/Input'

Vite 可以并行加载这些独立模块。没有瀑布流,速度明显更快。

如果你实在想用 barrel file 保持代码整洁,可以考虑用 Rolldown 的 Full Bundle Mode。打包模式下,瀑布流问题会被消解——所有模块都被打包成单个文件,不存在请求链。

4.3 减少 Resolve 操作

Vite 每次处理 import 语句,都要做 resolve:找到文件的实际路径。这个过程涉及检查 node_modules、尝试各种扩展名、处理路径别名。

减少 resolve 次数,可以加快编译速度。

显式写扩展名

// ❌ 隐式扩展名
import Button from './components/Button'

// ✅ 显式扩展名
import Button from './components/Button.tsx'

显式写扩展名,Vite 就不用尝试 .ts.tsx.js.jsx 各种可能了。

减少路径别名

// vite.config.ts
export default defineConfig({
  resolve: {
    alias: {
      '@': '/src',
      '@components': '/src/components',
      '@utils': '/src/utils',
      '@hooks': '/src/hooks',
      '@api': '/src/api'
    }
  }
})

每个别名都会增加 resolve 的工作量。建议保留一两个主要的别名(比如 @),其他的用相对路径。

4.4 原生插件与 Oxc Transform

Vite 6 引入了原生插件支持。用 Rust 写的插件比 JavaScript 插件快得多。

启用方式:

export default defineConfig({
  experimental: {
    enableNativePlugin: true
  }
})

不过这个功能还在实验阶段,大部分插件还不支持原生模式。

另一个值得关注的是 Oxc Transform。Oxc 是一个 Rust 写的 JavaScript/TypeScript 编译工具链。@vitejs/plugin-react v5+ 版本默认使用 Oxc 的 transform,比 Babel 快不少。

如果你用了 React 插件,确保升级到 v5+:

{
  "dependencies": {
    "@vitejs/plugin-react": "^5.0.0"
  }
}

Oxc 的 transform 不支持所有 Babel 特性(比如自定义 Babel 插件)。如果你有特殊的 Babel 配置,可能需要在插件里显式启用 Babel:

import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [
    react({
      babel: {
        // 强制使用 Babel
        plugins: ['your-babel-plugin']
      }
    })
  ]
})

结论

说了这么多,核心就几件事:

Environment API 改变了 Vite 的架构,但对普通项目影响有限。主要是框架作者受益,间接让你有更多部署选择。

Rolldown 是真正的性能飞跃。10 倍以上的构建加速、统一的插件系统、开发生产一致性——这些是实实在在的改进。Linear 从 46 秒到 6 秒不是吹的。

ESM 模块联邦 还在演进中。社区方案成熟可用,官方方案还在 RC。微前端场景可以先用 vite-plugin-federation,等 Rolldown 方案稳定再切换。

性能优化 的核心是减少瀑布流、预热高频文件、减少 resolve 操作。Rolldown 的 Full Bundle Mode 会改变很多优化策略——打包模式下,这些问题会被打包器自动处理。

迁移建议

  • 生产项目:先用 rolldown-vite 测试兼容性,没问题再等 Vite 8 正式版升级
  • 新项目:直接上 Vite 8 Beta,享受 Rolldown 的性能红利
  • 微前端项目:用 vite-plugin-federation,等 Rolldown 原生方案稳定

Vite 的工具链正在快速演进。从 esbuild + Rollup 双 bundler 到统一的 Rolldown,从 Webpack 兼容的模块联邦到原生支持,这些都是前端基建的重要变化。保持关注,适时升级,你的项目会跑得更快、更稳。

常见问题

Vite 6 的 Environment API 对普通项目有啥影响?
直接影响有限。Environment API 主要面向框架作者,让 Nuxt、Astro 等框架更优雅地支持 Cloudflare Workers、Deno 等边缘环境。普通 SPA/MPA 项目配置不变,Vite 保持向后兼容。间接好处是:你会有更多部署选择。
Rolldown 真的能让构建快 10 倍吗?
实测数据支持这个说法。Vite 8 Beta 公告里 Linear 项目从 46 秒降到 6 秒(87% 提升)。我在 3000+ 文件的 monorepo 实测是 7 倍提升。性能增益取决于项目规模——越大越明显。
现在要用 Module Federation,选哪个方案?
生产项目推荐 vite-plugin-federation(3000+ stars,稳定成熟)。新项目可以尝鲜 Rolldown 原生方案(RC 阶段)。两个方案都兼容 Webpack 5,可以和 Webpack 项目互操作。
升级 Vite 6 需要注意啥?
主要三点:1)Node.js 版本要 18.18.0+;2)resolve.conditions 默认值变了,手动配过的需要检查;3)Sass 现代 API 默认启用,自定义函数可能报错。大部分项目就是改个版本号的事。
Vite 6 性能优化有哪些实用技巧?
核心四招:预热高频文件(warmup 配置)、避免 Barrel Files(直接导入)、显式写扩展名(减少 resolve)、升级 React 插件到 v5+(用 Oxc transform)。Rolldown 的 Full Bundle Mode 会自动处理瀑布流问题。
什么时候该用 Module Federation?
多团队协作的大型项目、需要独立部署的微前端架构才适合。普通项目用模块联邦反而增加复杂度——要协调版本依赖、维护联邦边界。简单 monorepo 或 npm 包共享可能就够了。

14 分钟阅读 · 发布于: 2026年4月18日 · 修改于: 2026年4月18日

评论

使用 GitHub 账号登录后即可评论