原生ES模块 + 按需编译 + esbuild预构建
2026-03-13 | Vite v6 源码解读
Vite(法语意为"快速")是下一代前端构建工具
传统打包工具(如 Webpack)需要先打包整个应用才能启动开发服务器
Vite 利用浏览器原生 ESM 能力,无需打包即可启动
Vite 直接利用浏览器的 ESM 能力,无需打包即可运行
<!-- index.html -->
<script type="module" src="/src/main.js"></script>
<!-- main.js -->
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
浏览器直接加载 /src/main.js,Vite 拦截请求并实时编译
| 对比项 | Webpack | Vite |
|---|---|---|
| 启动时间 | 30-60秒 | 300-500ms |
| 打包方式 | 全量打包 | 按需编译 |
| HMR速度 | 1-3秒 | 50-100ms |
| 内存占用 | 高(全量编译) | 低(按需编译) |
Vite 只编译当前页面请求的文件,而不是整个应用
/src/App.vuetransformMiddlewarePluginContainer 执行插件链esbuild 编译 TypeScript/JSX@vitejs/plugin-vue 编译 Vue SFCVite 使用 esbuild 预构建第三方依赖,提升加载性能
# 预构建缓存位置
node_modules/.vite/deps/
├── vue.js
├── lodash.js
└── _metadata.json
esbuild 是用 Go 语言编写的 JavaScript 打包器,比 Webpack 快 100 倍
| 工具 | 打包速度 | 内存占用 | 语言 |
|---|---|---|---|
| Webpack 5 | 1x(基准) | 高 | JavaScript |
| Rollup | 2-3x | 中 | JavaScript |
| esbuild | 100x | 低 | Go |
| Vite | 100x(开发) | 低 | Go + JavaScript |
Vite 在多个环节使用 esbuild 提升性能
// vite.config.ts
export default {
esbuild: {
jsxFactory: 'h',
jsxFragment: 'Fragment',
jsxInject: `import React from 'react'`
}
}
| 对比项 | Babel | esbuild |
|---|---|---|
| 编译速度 | 慢(JavaScript) | 快 100 倍(Go) |
| AST 操作 | ✅ 支持 | ❌ 不支持 |
| 插件生态 | ✅ 丰富 | ⚠️ 有限 |
| 兼容性 | ✅ 完整 | ⚠️ 大部分 |
ViteDevServer 是 Vite 开发服务器的核心类
// packages/vite/src/node/server/index.ts
export interface ViteDevServer {
// HTTP 服务器
httpServer: http.Server | null
// WebSocket 服务器(用于 HMR)
ws: WebSocketServer
// 模块图(依赖关系)
moduleGraph: ModuleGraph
// 插件容器
plugins: Plugin[]
// 配置对象
config: ResolvedConfig
// 核心方法
transformRequest(url: string): Promise<TransformResult | null>
transformIndexHtml(url: string, html: string): Promise<string>
ssrLoadModule(url: string): Promise<unknown>
}
ModuleGraph 管理所有模块的依赖关系,用于 HMR
// packages/vite/src/node/server/mixedModuleGraph.ts
export class ModuleGraph {
// URL → ModuleNode 映射
urlToModuleMap = new Map<string, ModuleNode>()
// 文件路径 → ModuleNode 映射
fileToModulesMap = new Map<string, Set<ModuleNode>>()
// 核心方法
getModuleByUrl(url: string): ModuleNode | undefined
getModulesByFile(file: string): Set<ModuleNode> | undefined
onFileChange(file: string): void
onFileDelete(file: string): void
invalidateModule(mod: ModuleNode): void
}
export interface ModuleNode {
// 模块 URL
url: string
// 文件绝对路径
file: string | null
// 模块类型
type: 'js' | 'css' | 'html' | 'asset'
// 导入的模块
importers: Set<ModuleNode>
// 被导入的模块
importedModules: Set<ModuleNode>
// 是否被 HMR 接受
isSelfAccepting: boolean
// 最后转换结果
transformResult: TransformResult | null
// HMR 时间戳
lastHMRTimestamp: number
}
ModuleGraph 用于计算 HMR 边界,确定需要更新的模块
PluginContainer 管理插件生命周期和钩子函数
// packages/vite/src/node/server/pluginContainer.ts
export interface PluginContainer {
// 解析模块 ID
resolveId(id: string, importer?: string): Promise<ResolvedId | null>
// 加载模块
load(id: string): Promise<LoadResult | null>
// 转换模块代码
transform(code: string, id: string): Promise<TransformResult | null>
// 触发钩子
options(): Promise<RollupOptions | null>
buildStart(): Promise<void>
buildEnd(): Promise<void>
}
Vite 内置了多个核心插件,处理不同类型的文件
| 插件名 | 功能 |
|---|---|
| vite:resolve | 解析模块路径 |
| vite:html-inline-proxy | 处理 HTML 内联脚本 |
| vite:css | 处理 CSS 文件 |
| vite:esbuild | 编译 TypeScript/JSX |
| vite:json | 处理 JSON 文件 |
| vite:wasm | 处理 WebAssembly |
插件按以下顺序执行,确保正确的处理流程
// 插件执行顺序示例
[
{ name: 'pre-plugin', enforce: 'pre' },
{ name: 'vite:resolve' },
{ name: 'user-plugin' },
{ name: 'vite:define' },
{ name: 'post-plugin', enforce: 'post' }
]
resolveConfig 解析并合并用户配置,生成最终的 ResolvedConfig
// packages/vite/src/node/config.ts
export async function resolveConfig(
inlineConfig: InlineConfig,
command: 'build' | 'serve',
defaultMode = 'development'
): Promise<ResolvedConfig> {
// 1. 加载配置文件
const config = await loadConfigFromFile()
// 2. 合并配置
const resolved = mergeConfig(defaults, config, inlineConfig)
// 3. 解析插件
const plugins = await resolvePlugins(resolved)
// 4. 解析环境变量
const env = loadEnv(resolved.mode, resolved.envDir)
// 5. 返回最终配置
return { ...resolved, plugins, env }
}
vite.config.jsvite.config.tsvite.config.mjsvite.config.mtscreateServer 创建 Vite 开发服务器实例
// packages/vite/src/node/server/index.ts
export async function createServer(
inlineConfig: InlineConfig = {}
): Promise<ViteDevServer> {
// 1. 解析配置
const config = await resolveConfig(inlineConfig, 'serve')
// 2. 创建 HTTP 服务器
const httpServer = await resolveHttpServer(config)
// 3. 创建 WebSocket 服务器
const ws = createWebSocketServer(httpServer, config)
// 4. 创建模块图
const moduleGraph = new ModuleGraph()
// 5. 创建插件容器
const container = await createPluginContainer(config)
// 6. 注册中间件
const middlewares = connect()
middlewares.use(transformMiddleware(server))
// 7. 返回服务器实例
return { config, httpServer, ws, moduleGraph, plugins, ... }
}
transformMiddleware 是 Vite 的核心中间件,负责转换请求
// packages/vite/src/node/server/middlewares/transform.ts
export function transformMiddleware(
server: ViteDevServer
): Connect.NextHandleFunction {
return async (req, res, next) => {
// 1. 解析 URL
const url = req.url!
// 2. 判断是否需要转换
if (isTransformable(url)) {
// 3. 调用 transformRequest
const result = await server.transformRequest(url)
// 4. 返回编译后的代码
res.setHeader('Content-Type', 'application/javascript')
res.end(result.code)
} else {
next()
}
}
}
async function transformRequest(
url: string,
server: ViteDevServer
): Promise<TransformResult> {
// 1. 从模块图获取模块
const mod = await server.moduleGraph.getModuleByUrl(url)
// 2. 检查缓存
if (mod?.transformResult && !isStale(mod)) {
return mod.transformResult
}
// 3. 解析模块 ID
const id = await server.pluginContainer.resolveId(url)
// 4. 加载模块
const loadResult = await server.pluginContainer.load(id)
// 5. 转换代码
const transformResult = await server.pluginContainer.transform(
loadResult.code,
id
)
// 6. 更新模块图
mod.transformResult = transformResult
return transformResult
}
Vite 使用智能缓存策略,平衡速度和准确性
// 依赖缓存示例
// 强缓存 1 年
Cache-Control: max-age=31536000, immutable
// 源码协商缓存
ETag: "xxx"
Last-Modified: "2026-03-13T04:00:00Z"
Vite 对请求进行多种优化,提升加载速度
Vite 在架构设计上使用了多种经典设计模式
Vite 的插件系统兼容 Rollup 插件,扩展性强
// 自定义插件示例
export default function myPlugin(): Plugin {
return {
name: 'my-plugin',
resolveId(id) {
if (id === 'virtual:my-module') {
return id
}
},
load(id) {
if (id === 'virtual:my-module') {
return 'export default "Hello World"'
}
},
transform(code, id) {
if (id.endsWith('.vue')) {
return transformVue(code)
}
}
}
}
Connect 中间件链,灵活处理 HTTP 请求
// 中间件链示例
const middlewares = connect()
middlewares.use(corsMiddleware())
middlewares.use(proxyMiddleware())
middlewares.use(transformMiddleware(server))
middlewares.use(serveStaticMiddleware())
middlewares.use(indexHtmlMiddleware())
// 每个中间件可以:
// 1. 处理请求并返回响应
// 2. 调用 next() 传递给下一个中间件
文件监听和 HMR 使用观察者模式
// Chokidar 监听文件变化
const watcher = chokidar.watch(root, {
ignored: ['**/node_modules/**', '**/.git/**']
})
watcher.on('change', (file) => {
// 通知 ModuleGraph
server.moduleGraph.onFileChange(file)
// 触发 HMR
const mods = server.moduleGraph.getModulesByFile(file)
server.ws.send({
type: 'update',
updates: handleHMR(mods)
})
})
使用工厂函数创建复杂对象
createServer() - 创建开发服务器createPluginContainer() - 创建插件容器createWebSocketServer() - 创建 WebSocket 服务器createModuleGraph() - 创建模块图// 工厂模式优势
const server = await createServer({
root: process.cwd(),
plugins: [vue(), react()]
})
// 封装复杂初始化逻辑
// 易于测试和扩展
Vite vs Webpack 冷启动性能对比(大型项目)
| 指标 | Webpack 5 | Vite 6 | 提升 |
|---|---|---|---|
| 冷启动时间 | 30-60秒 | 0.3-0.5秒 | 100x |
| HMR 速度 | 1-3秒 | 50-100ms | 20-30x |
| 内存占用 | 1-2GB | 100-200MB | 10x |
| 首次加载 | 5-10秒 | 1-2秒 | 5x |
充分发挥 Vite 性能的推荐做法
避免这些会影响性能的做法
// ❌ 错误:全量导入
import _ from 'lodash' // 70KB
// ✅ 正确:按需导入
import debounce from 'lodash/debounce' // 2KB
// ❌ 错误:同步导入大模块
import hugeModule from './huge-module'
// ✅ 正确:动态导入
const hugeModule = await import('./huge-module')
// ❌ 错误:禁用依赖预构建
optimizeDeps: { exclude: ['vue'] }
// ✅ 正确:让 Vite 自动优化
// 不配置 optimizeDeps
合理配置依赖预构建,提升加载速度
// vite.config.ts
export default {
optimizeDeps: {
// 预包含依赖
include: ['vue', 'vue-router', 'pinia'],
// 排除不需要预构建的包
exclude: ['your-linked-package'],
// 强制重新构建
force: false
}
}
生产环境使用 Rollup 打包,确保最优性能
调试 Vite 项目的常用方法
# 启动调试模式
vite --debug
# 查看模块依赖
vite --force
# 分析打包结果
vite build --mode analysis
# 查看预构建依赖
vite optimize --force
Vite 冷启动优化的核心思想:利用浏览器原生能力 + 按需编译
| 工具 | 开发模式 | 生产构建 | 适用场景 |
|---|---|---|---|
| Vite | Native ESM | Rollup | 现代 Web 应用 |
| Webpack | 打包模式 | Webpack | 复杂企业应用 |
| Parcel | 打包模式 | Parcel | 零配置项目 |
| Snowpack | Native ESM | 打包可选 | 已停止维护 |
从 Webpack 迁移到 Vite 的注意事项
Vite 拥有活跃的社区和丰富的插件生态
感谢阅读!
本文基于 Vite v6 源码分析