抛几个问题大家先聊聊
-
大家心目中的vite是个什么样子
-
vite快在哪
-
vite 开发环境和生成环境都用什么打包 为啥不能统一
一、Vite 产生背景
1. 传统构建工具的核心痛点(webpack有啥痛点)
以 Webpack 为代表的传统工具,因 "全量打包" 模式难以适配复杂项目,主要痛点集中在四点:
● 🚫 开发体验差:冷启动达分钟级,热更新延迟随模块量增长,常丢失开发状态
● ⚡ 性能瓶颈明显:JS 编写的工具占用 CPU / 内存高,多项目并行时设备压力大
● 🔧 适配成本高:需兼容多模块格式(CJS/UMD/ESM),配置 TypeScript 等功能步骤繁琐
● 🕸️ 未利用浏览器新能力:2018 年后浏览器原生支持 ESM,但传统工具未借力优化
2. Vite 诞生的 3 大技术基石(vite有啥优势)
Vite 的出现依赖前端生态三大关键进展,缺一不可:
- 🌐 浏览器原生 ESM 普及
支持
- 🔨 编译工具语言革新
2020 年 Go 语言编写的 esbuild 发布,依赖预构建速度比 JS 工具快 10-100 倍,解决传统工具性能瓶颈。
- 🧩 构建理念升级
开发环境借鉴 Snowpack "依赖预构建" 思路,生产环境依托 Rollup 成熟插件生态,实现 "按需编译" 的新型构建模式。
3. Vite 诞生历程与关键决策(vite时间线)
Vite 从解决 Vue 生态痛点起步,逐步发展为跨框架通用工具:
● 📅 初始动机:2019 年 Vue 3 开发中,模块激增导致 Webpack 启动慢,亟需适配现代框架的轻量工具。
● 🚩 关键时间节点:
● 2020.04:Vite 1.0 发布,仅支持 Vue 项目,验证 ESM 开发模式可行性;
● 2021.02:Vite 2.0 重构,成为跨框架工具,引入 Rollup 负责生产构建;
● 2022-2023:3.0/4.0/5.0 版本持续优化性能,完善生态兼容(如支持 React、Svelte 等)。
● 🎯 核心决策:分模块差异化处理
依赖用 esbuild 预构建 + 源码开发时按需编译 + 全流程缓存,平衡速度与兼容性。
4. 构建模式对比流程图(webpack vs vite)
通过流程图直观对比传统工具与 Vite 的核心差异,重点关注 "是否全量打包""更新方式" 两个维度:
4.1 传统 Bundle 模式(以 Webpack 为例)
4.2 Vite 构建模式(开发 + 生产分离)
5. Vite 核心价值总结 (总结)
Vite 之所以能成为前端构建工具新选择,核心价值体现在四方面:
-
🔄 范式革新:开发 / 生产分离优化(ESM 按需编译 + Rollup 生产打包),兼顾速度与产物质量;
-
⚡ 性能突破:冷启动时间从分钟级压缩至秒级,大型项目开发效率提升显著;
-
🚀 体验升级:零配置开箱即用,HMR 保持应用状态,减少开发流程中断;
-
🌍 生态兼容:支持 Vue/React/Svelte 等多框架,兼容 Rollup 插件,降低迁移成本。
二. Vite 核心特性解析
Vite 颠覆传统构建工具的核心在于利用现代浏览器能力与分层优化策略,其三大核心特性共同实现了 "开发极速响应、生产高效输出" 的体验升级。
2.1 特性一:极速冷启动(毫秒级启动)
传统工具需全量打包后启动服务,而 Vite 通过 "依赖预构建 + 源码按需加载" 实现极速启动,启动时间不受项目体积线性影响。
2.1.1 实现原理
- 模块分层处理
首次启动时将项目模块拆分为两类,针对性优化:
● 依赖模块:开发中不变的纯 JS 依赖(如 Lodash、Vue 核心库),多含 CJS/UMD 格式,需统一转换为 ESM 并合并减少请求量。
● 源码模块:频繁编辑的业务代码(含 JSX、Vue 组件等),直接以原生 ESM 格式提供,浏览器请求时才按需编译。
- esbuild 预构建依赖
采用 Go 语言编写的 esbuild 处理依赖,速度比 JS 工具快 10-100 倍,预构建结果存入缓存(node_modules/.vite),二次启动直接复用。
- 浏览器接管部分打包工作
通过
2.1.2 冷启动流程可视化
2.2 特性二:精准热模块替换(HMR)
Vite 的 HMR 基于原生 ESM 实现,更新速度不随项目体积增长而下降,且能保持应用运行状态。
2.2.1 核心机制
- 模块依赖图追踪
启动时构建 moduleGraph 记录模块间依赖关系(如 A 依赖 B、B 依赖 C),每个模块对应唯一 ModuleNode 对象,包含转换结果与依赖链信息。
packages/vite/src/server/moduleGraph.ts
- 精准失效范围
文件修改后,仅使变更模块及其最近的 HMR 边界(如 Vue 组件的
- WebSocket 实时通信
● 用户修改文件后被 server 端的监听器监听到,监听器遍历文件对应的模块,计算出热更新边界
● server 端通过 websocket 向 client 发送热更新信号
● client 对旧模块进行失活,向 server 请求最新的模块资源
● server 收到请求后将模块代码转换为 js,并将转换后的代码返回给 client
● client 执行返回后的代码,调用更新函数更新页面内容
- 缓存加速
源码模块通过 304 Not Modified 协商缓存,依赖模块通过 immutable 强缓存,避免重复请求。
2.2.2 HMR 工作流程可视化
2.3 特性三:开发与生产双环境优化
Vite 采用 "开发按需编译、生产优化打包" 的差异化策略,兼顾开发效率与生产性能。
2.3.1 双环境设计逻辑
| 维度 | 开发环境(dev) | 生产环境(build) |
|---|---|---|
| 核心目标 | 极速启动、实时反馈 | 产物体积小、加载快、兼容性强 |
| 实现方式 | 原生 ESM 按需编译 + esbuild 预构建 | Rollup 优化打包 + 多维度性能优化 |
| 关键操作 | 模块缓存、HMR 局部更新 | Tree-shaking、代码分割、压缩、预加载注入 |
| 工具依赖 | Koa 服务器、WebSocket、chokidar | Rollup、Terser、CSSNano |
2.3.2 生产环境优化细节
- Rollup 打包核心
未采用 esbuild 生产打包的原因:Rollup 拥有更成熟的插件生态与更优的代码分割策略,能实现更精细的 Tree-shaking(剔除无用代码)。未来计划迁移至 Rust 编写的 Rolldown,进一步提升性能。
- 智能代码分割
自动拆分公共依赖(如 Vue 核心库)与业务代码,生成独立 chunk,利用浏览器缓存提升二次加载速度。
- 资源优化
● 压缩:JS 用 Terser 压缩,CSS 用 CSSNano 处理;
● 预加载:自动生成 ,提前加载关键模块;
● 兼容性:通过 @vitejs/plugin-legacy 生成 ES5 代码,适配旧浏览器。
为啥不用esbuild在生产环境
● 代码分割(Code Splitting)能力较弱:esbuild 的代码分割逻辑相对简单,对动态导入(import())的处理、公共模块提取(splitChunks)等高级需求支持不足,而现代前端项目(尤其是大型应用)依赖灵活的代码分割来优化加载性能。
● 生态兼容性有限:esbuild 的插件系统不如 Rollup 成熟,许多前端生态中常用的工具(如处理 CSS 模块化、静态资源、特定框架特性的插件)对 esbuild 的适配不够完善,而 Rollup 拥有丰富的插件生态,能更好地兼容前端工程化的复杂需求。
● 对非 ESM 模块的处理能力较弱:虽然 esbuild 支持转换 CommonJS 模块,但在处理复杂依赖关系(如循环依赖、动态 require)时,可能出现与 Webpack/Rollup 不一致的行为,存在兼容性风险。
2.3.3 双环境流程对比
2.4 特性总结:为何 Vite 能实现 "快且优"?
-
理念革新:让浏览器参与模块解析,将传统打包工具的 "预打包" 改为 "按需编译",从根源上提升启动速度。
-
技术选型精准:esbuild 处理依赖、Rollup 负责生产打包、WebSocket 实现 HMR,每一步都采用当前最优工具链。
-
分层优化思维:针对 "开发 - 生产""依赖 - 源码" 的不同特性设计差异化策略,既满足开发效率又保证生产性能。
三、 Vite 各版本对比及 Demo 展示
3.1版本演进核心脉络与定位
Vite 的版本迭代围绕「性能突破」与「架构统一」两大主线展开,可划分为三个关键阶段:
-
基础奠基期(V4.x):验证「非打包开发」核心模式,奠定极速启动基础
-
生态拓展期(V5.x-V6.x):完善框架适配与工具链集成,暴露混合架构瓶颈
-
架构重构期(V7.x-V8 Beta):引入 Rust 工具链,实现开发 / 生产流程统一
3.2关键版本核心特性对比
| 维度 | V4.x(奠基期) | V5.x-V6.x(拓展期) | V7.x(转型期) | V8 Beta(重构期) |
|---|---|---|---|---|
| 核心架构 | esbuild 预打包 + Rollup 生产构建 | 保留双工具架构,优化协作逻辑 | 引入 Rolldown 试验性支持 | 全 Rolldown 驱动,彻底替代双工具 |
| Node 支持 | Node.js 14.18+ | Node.js 16.14+ | Node.js 20.19+/22.12+(弃用 18) | 同 V7,兼容 LTS 版本 |
| 框架适配 | Vue/React/Svelte 核心支持 | 新增 Marko 模板,RedwoodSDK 整合 | 完善 Vue 3.5/React 19 适配 | 全框架兼容,支持微前端联邦架构 |
| TypeScript 能力 | 基础 TS 转译,依赖 esbuild | 内置 TS 5.8,支持常量枚举内联 | 集成 Oxc TS 解析,类型检查提速 30% | 原生 TS 类型优化,支持增量编译 |
| 性能优化点 | 冷启动 161ms(对比 Webpack 快 11.7 倍) | 解析逻辑优化,冷启动比 V4.2 提升 70% | 生产构建速度提升 30%,热更新 < 50ms | 跨块优化提速 15 倍,打包体积降 20% |
| 关键新特性 | HMR 模块依赖图追踪 | 模块联邦支持,barrel 文件优化 | 新增 buildApp 钩子,Vite DevTools 开发 | 全捆绑模式,原生 Importmaps 支持 |
3.3. 核心架构迭代解析
| 版本阶段 | 架构示意图 | 核心痛点解决 |
|---|---|---|
| V4.x-V6.x | 红色虚线框:开发用 esbuild、生产用 Rollup,工具链割裂导致环境差异黄色感叹号:Rollup 单线程处理大型项目时,构建速度瓶颈明显 | |
| V7.x | 过渡特性标注:绿色模块:新增的 Rolldown 试验性功能,主打性能提升黄色模块:优化后的 Dev Server,内存占用降低 30%分支逻辑:保留双工具链选项,平衡兼容性与性能 | |
| V8 Beta | 蓝色粗框:Rolldown 统一工具链,消除环境差异绿色模块:多线程 + 增量打包,性能核心产物体积比 V6.x 降 20%,无需手动配置 vendor |
3.4. 大型项目性能实测(复杂多应用工程)
| 指标 | V4.x | V6.x | V7.x | V8 Beta |
|---|---|---|---|---|
| 开发冷启动时间 | 2.8s | 1.5s | 0.9s | 0.3s |
| 生产构建时间 | 3m12s | 2m0s | 1m15s | 8s |
| 热更新响应时间 | 120ms | 80ms | 45ms | 20ms |
| 内存占用 | 180MB | 120MB | 90MB | 42MB |
数据来源:Vite 官方 benchmark 及 PayFit、掘金社区实测案例综合整理
3.5. 各版本适用场景
● V4.x:维护旧项目,依赖 Node.js 18 及以下环境
● V6.x:中型项目稳定运行,需 Marko/Redwood 生态支持
● V7.x:追求性能提升,可接受 Rust 工具链过渡适配
● V8 Beta:大型项目 / 微前端架构,需极致构建性能
3.6. 迁移成本与收益对比
| 迁移路径 | 核心改动点 | 预期收益 | 潜在风险 |
|---|---|---|---|
| V4→V6 | 升级 Node.js 至 16+,适配 TS 5.8 | 冷启动提速 46%,生态工具更丰富 | 部分旧插件兼容性问题 |
| V6→V7 | 升级 Node.js 至 20+,适配 Rolldown 试验模式 | 生产构建提速 40%,热更新延迟减半 | 少数第三方库导入顺序问题 |
| V7→V8 Beta | 移除 Rollup 配置,启用全捆绑模式 | 构建速度提升 15 倍,打包体积降 20% | 部分插件需迁移至 Rust 原生实现 |
3.7. 7+版本演进核心优势
-
性能质变节点:V7.x 引入 Rolldown 标志着性能提升从「优化迭代」进入「架构重构」阶段,V8 Beta 实现质的飞跃
-
架构统一价值:全 Rolldown 驱动解决了 Vite 诞生以来的「开发 / 生产环境不一致」核心痛点
-
生态适配节奏:每个大版本均保持对主流框架的兼容性,V8 将完成从工具到生态的全面升级
参考 Vite 官方路线图:2025 年底 V8 正式版将实现 Rolldown 全量启用,届时 V4-V7 版本将逐步进入维护期
3.8. 快速搭建各版本项目demo
perl
# Vite 3(需指定版本)
npm create vite@3 my-v3-app -- --template vue
# Vite 4
npm create vite@4 my-v4-app -- --template vue
# Vite 5
npm create vite@5 my-v5-app -- --template vue
# Vite 6
npm create vite@6 my-v6-app -- --template vue
# Vite 7
npm create vite@7 my-v7-app -- --template vue
四、vite4核心源码解析
4.1、Vite 4 核心架构与源码组织
Vite 4 采用 monorepo 结构(基于 pnpm workspace),核心代码集中于 packages/vite 目录,整体架构可划分为五大核心模块,各模块职责明确且协同联动。
4.2. 核心模块概览
| 模块路径 | 核心职责 | 关键依赖 / 工具 |
|---|---|---|
| src/node/cli.ts | 命令行入口,解析参数分发命令 | cac(命令行解析工具) |
| src/node/config/ | 配置解析与合并,支持多环境配置 | - |
| src/node/server/ | 开发服务器实现,集成 HMR 与中间件 | connect(中间件框架)、chokidar(文件监听) |
| src/node/build/ | 生产构建流程,基于 Rollup 实现 | Rollup 3、esbuild |
| src/node/plugin/ | 插件系统核心,定义钩子与容器 | - |
4.3. 核心数据结构
● ModuleGraph(src/node/server/moduleGraph.ts):维护模块依赖关系的核心数据结构,记录 URL 与文件路径映射、模块依赖链及 HMR 状态,是按需编译与热更新的基础。
● PluginContainer(src/node/pluginContainer.ts):插件容器,统一调度插件钩子执行,实现模块解析、转换等流程的可扩展性。
4.4、核心流程源码解析
Vite 4 的核心能力集中体现在开发环境启动、模块按需编译、热更新(HMR) 与生产构建四大流程,以下结合源码片段深度拆解。
4.4.1. 开发服务器启动流程(vite dev)
启动流程是 Vite 4 极速体验的起点,核心是初始化配置、构建中间件链与启动 HMR 服务,源码入口为 src/node/cli.ts,关键逻辑在 createServer 函数中实现。
关键步骤与源码
- 命令行解析与配置合并
scss
// src/node/cli.ts 简化逻辑
async function createServer(inlineConfig = {}) {
// 1. 解析配置:合并默认配置、用户配置、环境变量
const config = await resolveConfig(inlineConfig, 'serve')
// 2. 创建中间件容器与 HTTP 服务器
const middlewares = connect()
const httpServer = await resolveHttpServer(config.server, middlewares)
// 3. 初始化 WebSocket 服务(HMR 通信通道)
const ws = createWebSocketServer(httpServer, config)
// 4. 创建文件监听器(监控源码与配置变化)
const watcher = chokidar.watch(root, resolvedWatchOptions)
// 5. 初始化模块依赖图
const moduleGraph = new ModuleGraph((url) => pluginContainer.resolveId(url))
// 6. 注册核心中间件(按顺序执行)
middlewares.use(timeMiddleware) // 响应时间统计
middlewares.use(corsMiddleware(config)) // 跨域处理
middlewares.use(proxyMiddleware(config)) // 代理配置
middlewares.use(transformMiddleware(config, moduleGraph, ws)) // 模块转换核心
middlewares.use(indexHtmlMiddleware(config, moduleGraph)) // HTML 处理
middlewares.use(errorMiddleware()) // 错误捕获
// 7. 初始化插件容器
await pluginContainer.buildStart({})
// 8. 初始化依赖预构建器(后台启动,不阻塞服务器启动)
await initDepsOptimizer(config, options.force, true);
return { server, moduleGraph, ws }
}
- 依赖预构建优化
Vite 4 默认启用 esbuild 处理依赖预构建,将 CommonJS 格式的依赖转换为 ESM 并缓存,避免浏览器兼容性问题,源码位于 src/node/depOptimizer/。预构建产物存储于 node_modules/.vite/deps,首次启动后会缓存,二次启动直接复用。
启动流程可视化
4.4.2. 模块按需编译流程(核心性能点)
Vite 4 区别于传统打包工具的核心是按需编译:浏览器请求模块时才触发编译,而非全量预打包,核心实现依赖 transformMiddleware 中间件。
关键逻辑与源码
- 请求拦截与模块解析
javascript
// src/node/server/middlewares/transform.ts 简化逻辑
async function transformMiddleware(req, res, next) {
const url = req.url
// 1. 忽略静态资源与非模块请求
if (isStaticAsset(url) || !req.headers.accept?.includes('text/javascript')) {
return next()
}
// 2. 从模块图获取或创建模块实例
let module = moduleGraph.getModuleByUrl(url)
if (!module) {
const resolved = await pluginContainer.resolveId(url)
module = await moduleGraph.createModule(resolved.id, url)
}
// 3. 执行插件转换(如 Vue SFC 解析、TS 转译)
const transformResult = await pluginContainer.transform(code, module.file)
// 4. 注入 HMR 客户端代码(开发环境)
if (!isProduction) {
transformResult.code += injectHmrClientCode(url)
}
// 5. 返回编译结果给浏览器
res.setHeader('Content-Type', 'application/javascript')
res.end(transformResult.code)
}
拦截模块请求浏览器的请求先经过 Vite 服务器的中间件链,transformMiddleware 会识别出 "需要编译的模块请求"(如 .vue、.ts、.jsx 等非原生 ESM 模块,或需要转换的 JS 模块)。
定位模块文件
通过 ModuleGraph(之前提到的模块依赖图)将请求的 URL(如 /src/App.vue)映射到本地文件系统的路径(如 ./src/App.vue),确认模块的物理位置。
调用插件处理(编译)
借助 PluginContainer(插件容器)调用对应插件的转换钩子(如 transform),对模块内容进行实时编译:
例如,.vue 文件会被 @vitejs/plugin-vue 解析为模板、脚本、样式三部分,分别编译为浏览器可执行的 JS 代码;
例如,.ts 文件会被 @vitejs/plugin-typescript 转换为 JS 代码。
处理依赖关系
编译过程中,若模块依赖其他模块(如 App.vue 中 import Button from './Button.vue'),transformMiddleware 会通过 ModuleGraph 记录这些依赖关系,为后续的热更新做准备。
返回编译结果
将编译后的代码(符合 ESM 规范)作为 HTTP 响应返回给浏览器,浏览器直接执行该模块。
- 插件转换机制
以 Vue 单文件组件(SFC)为例,@vitejs/plugin-vue 插件通过 transform 钩子拦截 .vue 文件请求,将其拆分为模板、脚本、样式三部分分别处理,再合并为浏览器可识别的 ESM 模块。
4.4.3. 热更新(HMR)流程
Vite 4 升级了 HMR 引擎,大型项目热更新延迟从 1200ms 降至 500ms 内,核心是"精确模块更新"而非全页刷新,依赖文件监听、模块依赖分析与 WebSocket 通信实现。
关键步骤与源码
- 文件变化监听与依赖分析
php
// vite/src/node/server/hmr.ts 核心逻辑简化版
async function handleHMRUpdate(file: string, server: ViteDevServer) {
const { ws, config, moduleGraph } = server
// 1. 确定受影响的模块
const mods = moduleGraph.getModulesByFile(file)
// 2. 根据文件类型执行不同更新策略
if (isCSSRequest(file)) {
// CSS热更新逻辑
await Promise.all(
Array.from(mods).map((mod) => {
return moduleGraph.invalidateModule(mod)
})
)
ws.send({
type: 'update',
updates: [{
type: 'css-update',
path: publicPath,
timestamp: Date.now()
}]
})
} else {
// JS/HTML等热更新逻辑
const update = await generateUpdate(mods, file, server)
ws.send({
type: 'update',
updates: update
})
}
}
- 客户端更新处理
浏览器端通过 import.meta.hot API 接收更新通知,替换模块并执行自定义更新逻辑(如 Vue 组件重新渲染):
javascript
// 客户端 HMR 逻辑(src/client/client.ts)
import.meta.hot.accept('./component.js', (newComponent) => {
// 替换组件并重新挂载
replaceComponent(newComponent.default)
})
HMR 流程可视化
4.4.4. 生产构建流程(vite build)
生产环境下,Vite 4 采用 Rollup 3 进行打包优化,核心是代码分割、压缩与兼容性处理,源码入口为 src/node/build/index.ts。
关键步骤
-
配置解析与构建准备:合并生产环境配置,确定目标浏览器与输出格式。
-
Rollup 配置生成:根据 Vite 配置自动生成 Rollup 配置,支持
build.rollupOptions深度定制。 -
插件适配与执行:将 Vite 插件转换为 Rollup 插件格式,执行模块转换与优化。
-
产物优化:默认启用 Terser 压缩 JS,CSS 压缩通过
cssnano实现,支持自定义压缩工具。
核心配置示例
arduino
// Vite 4 生产构建配置
export default {
build: {
target: 'es2015', // 目标浏览器兼容性
minify: 'terser', // 启用 Terser 压缩
rollupOptions: {
// 自定义代码分割策略
output: {
manualChunks: {
vendor: ['vue', 'vue-router'], // 第三方依赖单独打包
utils: ['lodash', 'dayjs']
}
}
}
}
}
4.5、Vite 4 核心技术亮点源码解析
4.5.1. HMR 性能优化(V4 核心升级点)
Vite 4 对 HMR 引擎进行了重构,通过差分更新与模块依赖缓存减少重复计算,源码关键优化点在 ModuleGraph 的 invalidateModule 方法中:
javascript
// src/node/server/moduleGraph.ts
function invalidateModule(module) {
// 仅标记变化模块,不清除整个依赖链缓存
module.invalidated = true
// 递归标记依赖模块,但跳过已缓存的无变化模块
for (const importer of module.importers) {
if (!importer.invalidated) invalidateModule(importer)
}
}
4.5.2. 中间件链设计(可扩展性核心)
Vite 4 中间件按固定顺序执行,确保请求处理的正确性,核心中间件功能如下表:
| 中间件 | 核心功能 | 源码路径 |
|---|---|---|
| transformMiddleware | 模块实时编译(TS/Vue 转译) | src/node/server/middlewares/transform.ts |
| indexHtmlMiddleware | HTML 入口处理与资源注入 | src/node/server/middlewares/indexHtml.ts |
| proxyMiddleware | 跨域代理与请求转发 | src/node/server/middlewares/proxy.ts |
| errorMiddleware | 全局错误捕获与格式化 | src/node/server/middlewares/error.ts |
4.6、核心流程总览流程图
Vite 4 的源码设计核心是"扬长避短":用 esbuild 处理快但不灵活的步骤(预构建、转译),用 Rollup 处理灵活但慢的生产打包,用中间件与插件系统保证可扩展性,最终实现"极速开发+优化产物"的双重目标。
五、Vite 7 核心源码解析
5.1、Vite 7 核心架构与源码组织
Vite 7 延续 monorepo 结构(基于 pnpm workspace),核心代码集中于 packages/vite 目录,在保留"开发服务器+生产构建"双核心的基础上,新增 Rust 引擎适配层与环境抽象层,形成"四层架构"体系。
5.2. 核心模块概览
| 模块路径 | 核心职责 | 关键技术 / 工具 |
|---|---|---|
| src/node/cli.ts | 命令行入口,解析参数并分发命令 | cac(命令行解析) |
| src/node/config/ | 配置解析与合并,支持多环境配置隔离 | 环境抽象 API |
| src/node/server/ | 开发服务器实现,集成 HMR 与中间件 | connect、chokidar |
| src/node/build/ | 生产构建核心,支持 Rolldown/Rollup 双引擎 | Rolldown(Rust)、Rollup 3 |
| src/node/plugin/ | 插件系统,兼容 Rollup 插件并扩展新钩子 | 插件过滤 API(withFilter) |
5.3. 核心数据结构升级
● ModuleGraph(src/node/server/moduleGraph.ts):新增 Rust 引擎依赖追踪能力,支持 Rolldown 模块解析结果与 JS 模块图的双向同步,解决双引擎依赖分析不一致问题。
● BuilderContext(src/node/build/builderContext.ts):统一构建上下文,封装引擎选择、产物优化等核心逻辑,屏蔽 Rolldown 与 Rollup 的调用差异。
● Environment(src/node/env/index.ts):环境描述对象,定义目标运行时(浏览器/Node/边缘)、兼容性标准等属性,为多环境构建提供基础。
5.4、核心流程源码解析
Vite 7 的核心突破集中于 Rolldown 构建流程、多环境适配场景,以下结合源码片段深度拆解。
5.4.1Rolldown 预构建优化
Vite 7 支持通过 Rolldown 处理依赖预构建,替代部分 esbuild 功能,尤其在 CJS 转 ESM 场景下性能提升显著。预构建逻辑位于 src/node/optimizer/rolldownDepPlugin.ts 调用 Rust 接口处理依赖转换,产物存储于 node_modules/.vite/deps,并生成引擎兼容的缓存元数据。
启动流程可视化
源码part1 part2
5.4.2. 生产构建流程(vite build)------ Rolldown 核心适配
生产构建是 Vite 7 性能革新的核心场景,默认提供 Rolldown 引擎选项(通过 rolldown-vite 包集成),构建速度较 Rollup 提升 3-7 倍,内存占用减少 40% 以上。
关键步骤与源码
- rolldown打包逻辑 part3
csharp
// src/node/build.ts 简化逻辑
async function buildEnvironment(environment) {
// 1. 创建一个新的ChunkMetadataMap实例,用于存储和管理构建过程中的chunk元数据
const chunkMetadataMap = new ChunkMetadataMap()
// 2. 解析Rolldown配置选项,将环境配置和chunk元数据映射传递给解析函数
// 注意变量名虽然是rollupOptions,但实际返回的是Rolldown的配置
const rollupOptions = resolveRolldownOptions(environment, chunkMetadataMap)
// 3. 检查是否处于监视模式(watch mode)
if (options.watch) {
// 4. 在控制台输出信息,告知用户正在监视文件变化
logger.info(colors.cyan(`\nwatching for file changes...`))
// 5. 解析输出目录,获取构建产物将被写入的目录路径
const resolvedOutDirs = getResolvedOutDirs(
root,
options.outDir,
options.rollupOptions.output, // 使用rollupOptions.output作为输出配置
)
// 6. 解析是否需要清空输出目录的设置
const emptyOutDir = resolveEmptyOutDir(
options.emptyOutDir, // 用户配置的emptyOutDir选项
root,
resolvedOutDirs, // 解析后的输出目录
logger,
)
// 7. 解析文件监视选项(Chokidar配置)
const resolvedChokidarOptions = resolveChokidarOptions(
{
// 8. 合并配置中的chokidar选项(虽然Rolldown没有这个选项,但为了向后兼容保留)
// @ts-expect-error 标记:chokidar选项在rolldown中不存在,但为了向后兼容而使用
...(rollupOptions.watch || {}).chokidar,
// @ts-expect-error 同样标记:用户配置的watch.chokidar选项
...options.watch.chokidar,
},
resolvedOutDirs, // 输出目录
emptyOutDir, // 是否清空输出目录
environment.config.cacheDir, // 缓存目录
)
// 9. 动态导入rolldown的watch函数
const { watch } = await import('rolldown')
// 10. 创建Rolldown的watcher实例,传入配置选项
const watcher = watch({
...rollupOptions, // 基础构建配置
watch: { // 监视模式特定配置
...rollupOptions.watch, // 合并原有watch配置
...options.watch, // 合并用户提供的watch配置
// 11. 将Chokidar配置转换为Rolldown的notify选项
notify: convertToNotifyOptions(resolvedChokidarOptions),
},
})
// 12. 监听watcher事件
watcher.on('event', (event) => {
// 13. 当构建开始时的处理
if (event.code === 'BUNDLE_START') {
logger.info(colors.cyan(`\nbuild started...`)) // 输出构建开始信息
chunkMetadataMap.clearResetChunks() // 清除并重置chunk元数据
}
// 14. 当构建结束时的处理
else if (event.code === 'BUNDLE_END') {
event.result.close() // 关闭构建结果,释放资源
logger.info(colors.cyan(`built in ${event.duration}ms.`)) // 输出构建耗时
}
// 15. 当发生错误时的处理
else if (event.code === 'ERROR') {
const e = event.error
enhanceRollupError(e) // 增强错误信息,使其更有用
clearLine() // 清除控制台当前行
logger.error(e.message, { error: e }) // 输出错误信息
}
})
// 16. 返回watcher实例,允许外部控制监视过程
return watcher
}
// 17. 非监视模式:使用rolldown进行单次构建
// write or generate files with rolldown
const { rolldown } = await import('rolldown') // 动态导入rolldown函数
startTime = Date.now() // 记录构建开始时间
// 18. 使用配置创建rolldown实例
bundle = await rolldown(rollupOptions)
// 19. 创建一个数组来存储构建输出结果
const res: RolldownOutput[] = []
// 20. 遍历所有输出配置(可能有多个输出配置)
for (const output of arraify(rollupOptions.output!)) {
// 21. 根据options.write决定是写入文件还是仅生成输出内容
// 如果options.write为true则调用bundle.write(),否则调用bundle.generate()
res.push(await bundle[options.write ? 'write' : 'generate'](output))
}
}
- 性能优化关键点
● 单一引擎架构:开发与生产环境统一使用 Rolldown 处理依赖解析与模块转换,避免双工具链的数据重复序列化/反序列化开销。
● Oxc 工具集集成:替代 esbuild 处理代码解析与转译,内存使用效率提升显著,大型项目构建内存占用可减少 100 倍。
5.4.3. 多环境适配流程(核心功能升级)
Vite 7 稳定了多环境 API,支持浏览器、Node、边缘服务器等多运行时目标
关键逻辑与源码通过代理将rollup转发到rolldown处理
javascript
export function setupRollupOptionCompat<
T extends Pick<BuildEnvironmentOptions, 'rollupOptions' | 'rolldownOptions'>,
>(
buildConfig: T,
): asserts buildConfig is T & {
rolldownOptions: Exclude<T['rolldownOptions'], undefined>
} {
// if both rollupOptions and rolldownOptions are present,
// ignore rollupOptions and use rolldownOptions
// 如果同时存在rollupOptions和rolldownOptions,忽略rollupOptions
buildConfig.rolldownOptions ??= buildConfig.rollupOptions
// proxy rolldownOptions to rollupOptions
// 通过代理将rollupOptions的访问转发到rolldownOptions
Object.defineProperty(buildConfig, 'rollupOptions', {
get() {
return buildConfig.rolldownOptions
},
set(newValue) {
buildConfig.rolldownOptions = newValue
},
configurable: true,
enumerable: true,
})
}
5.4、核心流程总览流程图
5.5、源码学习建议
-
入门路径:从
vite dev启动流程切入,先理解createServer函数的整体逻辑,再深入中间件与模块图实现。 -
核心突破点:重点分析
transformMiddleware如何实现按需编译,以及ModuleGraph如何维护依赖关系。 -
调试技巧:通过
DEBUG=vite:* vite dev打印调试日志,追踪请求处理与 HMR 触发流程。
4 . 拥抱ai 配合aiide做源码解析梳理核心流程细节
5 . 先脉络后细节