Appearance
Vite 架构分析
高层架构
整体架构图
┌─────────────────────────────────────────────────────────────┐
│ 用户浏览器 │
└─────────────────────────────────────────────────────────────┘
│
│ HTTP 请求
▼
┌─────────────────────────────────────────────────────────────┐
│ Vite 开发服务器 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 请求拦截器 │ │
│ │ - 解析 URL │ │
│ │ - 判断请求类型 │ │
│ │ - 路由到对应的处理器 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 资源处理器 │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ HTML 处理器 │ │ JS 处理器 │ │ CSS 处理器 │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ 静态资源处理 │ │ HMR 处理器 │ │ 代理处理器 │ │ │
│ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 插件系统 │ │
│ │ - 转换器(Transformers) │ │
│ │ - 解析器(Resolvers) │ │
│ │ - 钩子(Hooks) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 依赖优化 │ │
│ │ - esbuild 预构建 │ │
│ │ - 缓存管理 │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
│ 文件系统
▼
┌─────────────────────────────────────────────────────────────┐
│ 项目源代码 │
│ - src/ │
│ - public/ │
│ - index.html │
│ - vite.config.js │
└─────────────────────────────────────────────────────────────┘生产环境架构
┌─────────────────────────────────────────────────────────────┐
│ 构建流程 │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Rollup 打包器 │ │
│ │ - 入口分析 │ │
│ │ - 模块解析 │ │
│ │ - 依赖图构建 │ │
│ │ - 代码分割 │ │
│ │ - Tree-shaking │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 代码转换 │ │
│ │ - TypeScript 编译 │ │
│ │ - JSX 转换 │ │
│ │ - CSS 预处理 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 优化处理 │ │
│ │ - 压缩 │ │
│ │ - 哈希命名 │ │
│ │ - 资源内联 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 输出 │ │
│ │ - dist/ │
│ │ - index.html │
│ │ - assets/ │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘核心模块
1. 开发服务器(Dev Server)
功能
- 处理 HTTP 请求
- 按需编译文件
- 提供 HMR
- 代理请求
核心代码结构
javascript
// 简化的开发服务器结构
class DevServer {
constructor(config) {
this.config = config
this.plugins = []
this.transformCache = new Map()
this.moduleGraph = new ModuleGraph()
}
// 启动服务器
async start() {
const server = createServer(this.config)
await server.listen()
}
// 处理请求
async handleRequest(req, res) {
const url = req.url
// 1. 检查是否是静态资源
if (this.isStatic(url)) {
return this.serveStatic(url)
}
// 2. 检查是否是 HTML
if (this.isHTML(url)) {
return this.transformHTML(url)
}
// 3. 检查是否是 JS/TS
if (this.isJS(url)) {
return this.transformJS(url)
}
// 4. 检查是否是 CSS
if (this.isCSS(url)) {
return this.transformCSS(url)
}
}
// 转换 JavaScript
async transformJS(url) {
// 1. 检查缓存
if (this.transformCache.has(url)) {
return this.transformCache.get(url)
}
// 2. 读取文件
const source = await fs.readFile(url)
// 3. 应用插件转换
let code = source
for (const plugin of this.plugins) {
if (plugin.transform) {
const result = await plugin.transform(code, url)
if (result) {
code = result.code || result
}
}
}
// 4. 缓存结果
this.transformCache.set(url, code)
return code
}
}2. 依赖预构建(Dep Pre-bundling)
功能
- 使用 esbuild 预构建依赖
- 优化依赖加载
- 缓存预构建结果
核心代码结构
javascript
// 简化的依赖预构建结构
class DepOptimizer {
constructor(config) {
this.config = config
this.cacheDir = path.join(config.root, 'node_modules/.vite')
}
// 扫描依赖
async scanDeps() {
const entry = this.config.root
const deps = await this.scanImports(entry)
return deps
}
// 预构建依赖
async preBundle(deps) {
const result = await esbuild.build({
entryPoints: Object.keys(deps),
bundle: true,
format: 'esm',
write: true,
outdir: this.cacheDir
})
return result
}
// 检查缓存
async checkCache() {
const cachePath = path.join(this.cacheDir, '_metadata.json')
if (!fs.existsSync(cachePath)) {
return false
}
const metadata = JSON.parse(fs.readFileSync(cachePath, 'utf-8'))
const currentHash = await this.computeHash()
return metadata.hash === currentHash
}
}3. 模块图(Module Graph)
功能
- 追踪模块依赖关系
- 管理 HMR
- 优化重新构建
核心代码结构
javascript
// 简化的模块图结构
class ModuleGraph {
constructor() {
this.modules = new Map()
this.urlToModuleMap = new Map()
this.idToModuleMap = new Map()
}
// 获取模块
getModuleByUrl(url) {
return this.urlToModuleMap.get(url)
}
// 创建模块
createModule(url) {
const module = {
id: this.generateId(url),
url,
imports: [],
importers: [],
transformResult: null,
lastHMRTimestamp: 0
}
this.modules.set(module.id, module)
this.urlToModuleMap.set(url, module)
this.idToModuleMap.set(module.id, module)
return module
}
// 更新模块
async updateModule(url) {
const module = this.getModuleByUrl(url)
if (!module) return
// 重新转换模块
const result = await this.transform(url)
module.transformResult = result
// 更新依赖关系
await this.updateImports(module, result.imports)
// 触发 HMR
await this.triggerHMR(module)
}
// 触发 HMR
async triggerHMR(module) {
const hmrPayload = {
type: 'update',
updates: [
{
type: 'js-update',
timestamp: Date.now(),
path: module.url,
acceptedPath: module.url
}
]
}
this.sendHMR(hmrPayload)
}
}4. 插件系统(Plugin System)
功能
- 扩展 Vite 功能
- 转换代码
- 解析模块
- 钩入构建流程
插件接口
javascript
// 插件接口
interface Plugin {
name: string
// 配置钩子
config?: (config: UserConfig) => UserConfig | void
configResolved?: (config: ResolvedConfig) => void
// 服务器钩子
configureServer?: (server: ViteDevServer) => void
transformIndexHtml?: (html: string) => string | Promise<string>
// 转换钩子
load?: (id: string) => LoadResult | Promise<LoadResult>
transform?: (code: string, id: string) => TransformResult | Promise<TransformResult>
// 解析钩子
resolveId?: (id: string, importer: string) => ResolveIdResult | Promise<ResolveIdResult>
// 构建钩子
buildStart?: () => void
buildEnd?: () => void
generateBundle?: () => void
}
// 示例插件
function myPlugin() {
return {
name: 'my-plugin',
transform(code, id) {
if (id.endsWith('.js')) {
// 转换代码
return {
code: code.replace(/foo/g, 'bar'),
map: null
}
}
}
}
}数据流
开发环境数据流
1. 用户访问页面
└─> 浏览器请求 index.html
2. Vite 返回 HTML
└─> HTML 中包含 <script type="module" src="/src/main.js">
3. 浏览器解析 HTML
└─> 发现 ES 模块导入
└─> 请求 /src/main.js
4. Vite 接收请求
└─> 读取 src/main.js
└─> 应用插件转换
└─> 返回转换后的代码
5. 浏览器执行代码
└─> 发现新的导入
└─> 递归请求依赖
6. 重复步骤 4-5
└─> 直到所有依赖加载完成
7. 用户修改文件
└─> Vite 检测到文件变化
└─> 重新转换修改的文件
└─> 通过 WebSocket 发送 HMR 更新
└─> 浏览器接收更新
└─> 热更新模块生产环境数据流
1. 运行构建命令
└─> vite build
2. Rollup 开始打包
└─> 分析入口文件
└─> 构建依赖图
3. 转换代码
└─> TypeScript 编译
└─> JSX 转换
└─> CSS 预处理
4. 优化代码
└─> Tree-shaking
└─> 代码分割
└─> 压缩
5. 生成输出
└─> 写入 dist/ 目录
└─> 生成 index.html
└─> 生成 assets/
6. 部署
└─> 上传 dist/ 到服务器
└─> 配置静态资源服务并发模型
开发环境并发
javascript
// Vite 使用异步 I/O 和事件循环
async function handleRequest(req, res) {
// 并发处理多个请求
const result = await Promise.all([
transformJS(url),
transformCSS(url),
loadAssets(url)
])
return result
}
// HMR 并发更新
async function handleFileChange(file) {
// 并发更新受影响的模块
const modules = await findAffectedModules(file)
await Promise.all(
modules.map(module => updateModule(module))
)
}生产环境并发
javascript
// Rollup 使用 Worker 进行并行处理
function build() {
// 并行处理多个入口
const results = await Promise.all(
entries.map(entry => buildEntry(entry))
)
return results
}
// 并行优化
async function optimize() {
await Promise.all([
optimizeJS(),
optimizeCSS(),
optimizeAssets()
])
}容错策略
开发环境容错
javascript
// 错误边界
async function transformJS(url) {
try {
const code = await fs.readFile(url)
return await transform(code)
} catch (error) {
// 返回错误信息
return `
throw new Error('${error.message}')
`
}
}
// HMR 容错
async function triggerHMR(module) {
try {
await updateModule(module)
sendHMRUpdate(module)
} catch (error) {
// 回退到整页刷新
sendFullReload()
}
}生产环境容错
javascript
// 构建错误处理
async function build() {
try {
await rollup.rollup(config)
} catch (error) {
// 记录错误
logError(error)
// 尝试恢复
if (canRecover(error)) {
await buildWithFallback()
} else {
throw error
}
}
}可扩展性杠杆
1. 插件系统
- 通过插件扩展功能
- 支持自定义转换器
- 支持自定义解析器
2. 配置系统
- 灵活的配置选项
- 支持多环境配置
- 支持配置继承
3. API 扩展
- 编程式 API
- 钩子系统
- 中间件支持
4. 生态集成
- 与主流框架集成
- 与主流工具集成
- 与主流服务集成
性能优化
开发环境优化
缓存策略
- 文件系统缓存
- 转换结果缓存
- 依赖预构建缓存
按需编译
- 只编译访问的文件
- 延迟编译未访问的文件
增量更新
- 只更新修改的模块
- 复用未修改的模块
生产环境优化
代码分割
- 路由级别分割
- 组件级别分割
- 动态导入
Tree-shaking
- 移除未使用的代码
- 优化依赖树
资源优化
- 压缩
- 哈希命名
- CDN 加速
总结
Vite 的架构设计充分利用了现代浏览器的能力,通过 ES 模块和按需编译实现了极速的开发体验。同时,通过 Rollup 和各种优化技术,保证了生产环境的性能和优化。插件系统提供了强大的扩展能力,使得 Vite 能够适应各种不同的应用场景。

扫描二维码关注"架构师AI杜"公众号,获取更多技术内容和最新动态
