This repository has been archived on 2026-05-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
obsidian/DEV/VITE/架构原理.md
T
2026-04-20 22:47:51 +08:00

904 lines
21 KiB
Markdown

---
tags: [DEV, VITE, architecture, internals]
create time: 2026-04-18
---
# Vite 架构原理
## 核心设计理念
Vite 的核心创新在于**利用浏览器原生能力和分层优化策略**,将开发环境和生产环境采用完全不同的处理方式。
```mermaid
graph TB
A[用户请求] --> B{环境判断}
B -->|开发环境| C[Dev Server]
B -->|生产环境| D[Pre-built Assets]
C --> E[ESM 按需编译]
E --> F[即时返回]
D --> G[Rollup 优化产物]
G --> H[CDN/HTTP 服务器]
```
## 开发环境架构
### 服务启动流程
```mermaid
sequenceDiagram
participant CLI as 用户命令行
participant Config as 配置加载器
participant Server as Dev Server
participant Plugin as 插件系统
participant Monitor as 文件监听器
CLI->>Config: 读取配置文件
Config->>Server: 创建服务器实例
Server->>Plugin: 注册所有插件
Plugin->>Server: 返回钩子函数
Server->>Monitor: 启动文件监听
Monitor->>Server: 建立连接
Server-->>CLI: 服务器启动完成
```
### HTTP 请求处理流程
```mermaid
graph TD
A[HTTP 请求] --> B[中间件层]
B --> C{请求类型判断}
C -->|HTML 文件| D[响应 HTML]
C -->|JS/TS 文件| E[transform 链]
C -->|CSS 文件| F[CSS 处理器]
C -->|静态资源| G[资源处理]
E --> H[Plugin 转换]
H --> I[返回编译后代码]
F --> I
G --> J[返回资源引用]
```
### 请求处理实现
```typescript
class ViteDevServer {
private pluginContainer: PluginContainer
private fileWatcher: FSWatcher
private moduleGraph: ModuleGraph
async handleRequest(req: IncomingMessage, res: ServerResponse) {
const url = req.url!
try {
// 1. 处理 HTML 入口文件
if (url.endsWith('.html')) {
await this.handleHtmlRequest(url, res)
return
}
// 2. 处理模块请求
if (this.isModuleRequest(url)) {
const module = await this.transformModule(url)
this.sendModuleResponse(module, res)
return
}
// 3. 处理静态资源
const asset = await this.resolveAsset(url)
if (asset) {
this.sendAssetResponse(asset, res)
return
}
} catch (error) {
this.handleError(error, res)
}
}
}
```
## 模块系统实现
### 模块图结构
```mermaid
graph LR
A[main.tsx] --> B[App.tsx]
A --> C[router.tsx]
B --> D[Header.tsx]
B --> E[Counter.tsx]
C --> F[Pages.tsx]
E --> G[useState.ts]
E --> H[useEffect.ts]
```
### 模块节点实现
```typescript
class ModuleNode {
public readonly id: string
public url: string
public file: string
// 依赖关系
public importers = new Set<ModuleNode>()
public importedModules = new Set<ModuleNode>()
public importedBindings: Record<string, string[]> = {}
// 转换结果
public transformResult: TransformResult | null = null
public lastHMRTimestamp = 0
// SSR 信息
public ssrModule: any = null
public ssrTransformResult: TransformResult | null = null
constructor(id: string) {
this.id = id
this.url = id
this.file = path.normalize(id)
}
}
class ModuleGraph {
private modules = new Map<string, ModuleNode>()
private fileToModulesMap = new Map<string, Set<ModuleNode>>()
async ensureEntryFromUrl(url: string): Promise<ModuleNode> {
const resolved = await this.resolveUrl(url)
return this.ensureModule(resolved.id, resolved.url)
}
async ensureModule(
id: string,
url: string,
ssr?: boolean
): Promise<ModuleNode> {
let module = this.modules.get(id)
if (!module) {
module = new ModuleNode(id)
this.modules.set(id, module)
// 建立文件映射
const file = path.resolve(id)
let fileModules = this.fileToModulesMap.get(file)
if (!fileModules) {
fileModules = new Set()
this.fileToModulesMap.set(file, fileModules)
}
fileModules.add(module)
}
return module
}
updateModule(module: ModuleNode, transformed: TransformResult) {
module.transformResult = transformed
module.lastHMRTimestamp = Date.now()
}
/**
* 失效模块及其导入者
*/
invalidateModule(mod: ModuleNode): void {
mod.transformResult = null
mod.ssrModule = null
mod.ssrTransformResult = null
// 级联失效所有导入者
const invalidators = new Set<ModuleNode>()
const queue: ModuleNode[] = [...mod.importers]
while (queue.length > 0) {
const importer = queue.pop()!
invalidators.add(importer)
// 如果导入者的代码需要重新编译
if (!importer.transformResult) {
importer.importers.forEach(dep => {
if (!invalidators.has(dep)) {
queue.push(dep)
}
})
}
}
}
/**
* 检测循环依赖
*/
hasCircularDependency(module: ModuleNode): boolean {
const visited = new Set<string>()
const stack = [module.id]
while (stack.length > 0) {
const currentId = stack.pop()!
if (visited.has(currentId)) {
console.warn(`[vite] Circular dependency detected: ${currentId}`)
return true
}
visited.add(currentId)
const currentModule = this.modules.get(currentId)
if (currentModule) {
currentModule.importedModules.forEach(dep => {
if (!visited.has(dep.id)) {
stack.push(dep.id)
}
})
}
}
return false
}
}
```
## ES Module 编译器
### 源码转换流水线
```mermaid
graph TD
A[原始源代码] --> B[Plugin Transform 钩子]
B --> C[语法转换]
C --> D[依赖注入]
D --> E[包装 ESM]
E --> F[生成 Source Map]
F --> G[返回处理后的代码]
```
### 依赖预构建
```typescript
class DepsOptimizer {
private depsCacheDir: string
private scanner: DepsOptimizer
async scanImports(): Promise<ScanResult> {
const entries = await this.getEntryPoints()
const discovered = await esbuild.context({
entryPoints: entries,
bundle: true,
write: false,
onEnd: (result) => {
const dependencies = this.extractDependencies(result.metafile)
this.updateOptimizedDeps(dependencies)
}
})
return discovered
}
async optimizeDeps(deps: Record<string, string>): Promise<void> {
const optimizedDeps = new Map<string, string>()
for (const [id, file] of Object.entries(deps)) {
try {
// 转换为 ESM
const result = await esbuild.build({
entryPoints: [file],
bundle: true,
format: 'esm',
target: 'esnext',
write: false,
packages: 'external'
})
optimizedDeps.set(id, file)
// 缓存到 disk
await this.saveOptimizedDep(id, result)
} catch (e) {
console.error(`Failed to optimize dependency: ${id}`, e)
}
}
}
async saveOptimizedDep(id: string, result: BuildResult): Promise<void> {
const outputPath = path.join(this.depsCacheDir, `${id}.js`)
const metaPath = path.join(this.depsCacheDir, `${id}.js.meta.json`)
await fs.writeFile(
outputPath,
result.outputFiles[0].text,
'utf-8'
)
await fs.writeFile(
metaPath,
JSON.stringify({
file: id,
src: path.basename(outputPath)
}),
'utf-8'
)
}
}
```
## 热模块替换 (HMR)
### HMR 工作机制
```mermaid
sequenceDiagram
participant File as 文件系统
participant Watcher as 监听器
participant Server as Dev Server
participant WS as WebSocket
participant Client as 浏览器客户端
File->>Watcher: 文件变更
Watcher->>Server: 触发 change 事件
Server->>Server: 失效相关模块
Server->>Server: 重新编译变更模块
Server->>WS: 发送 HMR 更新
WS->>Client: 接收更新通知
Client->>Client: 执行模块替换
Client->>Server: 发送确认消息
```
### HMR 协议
```typescript
// 服务端发送的 HMR 消息类型
interface HMRCustomEvent {
type: 'custom'
event: string
data: any
}
interface HMRUpdateEvent {
type: 'update'
updates: Array<{
type: 'js-update' | 'css-update' | 'static-update'
path: string
acceptedPath: string
timestamp: number
}>
}
interface HMRConnectedEvent {
type: 'connected'
}
interface HMRPruneEvent {
type: 'prune'
paths: string[]
}
// 客户端处理实现
class HMRClient {
private ws: WebSocket
private pendingImports = new Map<string, Promise<void>>()
async handleUpdate(updates: HMRUpdateEvent['updates']) {
for (const update of updates) {
switch (update.type) {
case 'js-update':
await this.handleJSModuleUpdate(update)
break
case 'css-update':
await this.handleCSSUpdate(update)
break
case 'static-update':
this.handleStaticUpdate(update)
break
}
}
}
private async handleJSModuleUpdate(update: Extract<HMRUpdateEvent['updates'][0], { type: 'js-update' }>) {
const { path, timestamp, acceptedPath } = update
// 使用浏览器原生 import API 重新导入模块
const importPromise = import(`${path}?t=${timestamp}`).then((mod) => {
// 查找模块的热替换处理器
const modUrl = acceptedPath || path
const modObject = window.__vite_module_cache__[modUrl]
if (modObject && modObject.hot) {
// 触发热替换处理器
modObject.hot.accept(mod)
// 执行清理回调
if (modObject.hot._dispose) {
modObject.hot._dispose()
}
}
})
this.pendingImports.set(path, importPromise)
}
}
```
### 组件级 HMR
```typescript
// React 组件的 HMR 实现
import { createHot } from '@vitejs/plugin-react/client'
// 在开发环境中,Vite 会自动注入
if (import.meta.hot) {
import.meta.hot.accept('./App.tsx', (newModule) => {
// React Fast Refresh 处理
const prevComponent = window.__vite_plugin_react_component__
window.__vite_plugin_react_component__ = newModule.default
// 触发组件重新渲染
window.__vite_plugin_react_rerender__()
})
}
```
## 插件系统架构
### 插件生命周期
```mermaid
graph TD
A[Config 阶段] --> B[ConfigResolved]
B --> C[ConfigureServer]
C --> D[BuildStart]
D --> E[Transform Phase]
E --> F[Load Phase]
F --> G[BuildEnd]
G --> H[CloseBundle]
```
### 插件容器实现
```typescript
class PluginContainer {
private plugins: Plugin[]
private hooks: Record<string, Function[]>
constructor(plugins: Plugin[]) {
this.plugins = plugins
this.hooks = {}
this.registerHooks(plugins)
}
private registerHooks(plugins: Plugin[]) {
const hookNames: validHooks[] = [
'buildStart', 'buildEnd',
'resolveId', 'load', 'transform',
'configureServer'
]
hookNames.forEach(hookName => {
this.hooks[hookName] = plugins
.map(plugin => plugin[hookName])
.filter(Boolean)
})
}
async resolveId(id: string, importer?: string): Promise<string | null> {
const resolveHooks = this.hooks['resolveId']
for (const hook of resolveHooks) {
const result = await hook.call(this, id, importer)
if (result) {
return result
}
}
return null
}
async load(id: string): Promise<string | null> {
const loadHooks = this.hooks['load']
for (const hook of loadHooks) {
const result = await hook.call(this, id)
if (result) {
return result
}
}
return null
}
async transform(code: string, id: string): Promise<TransformResult | null> {
const transformHooks = this.hooks['transform']
let result = { code, map: null }
for (const hook of transformHooks) {
const transformed = await hook.call(this, result.code, id)
if (transformed) {
result = {
code: transformed.code,
map: transformed.map || result.map
}
}
}
return result.code !== code ? result : null
}
}
```
## 构建系统 (生产环境)
### Rollup 集成
```mermaid
graph TD
A[入口文件] --> B[依赖图构建]
B --> C[模块解析]
C --> D[代码转换]
D --> E[代码分割]
E --> F[Tree Shaking]
F --> G[minification]
G --> H[输出生成]
```
### 构建流程实现
```typescript
class BuildSystem {
async build(config: ResolvedConfig): Promise<BuildResult> {
// 1. 分析入口文件
const entries = this.resolveEntries(config)
// 2. 构建模块图
const moduleGraph = await this.buildModuleGraph(entries)
// 3. 代码优化
const optimizedModules = await this.optimizeModules(moduleGraph)
// 4. 代码分割
const chunks = this.splitChunks(optimizedModules)
// 5. 压缩混淆
const minifyResults = await this.minifyChunks(chunks)
// 6. 生成输出
const outputs = this.generateOutputs(minifyResults)
return { modules: outputs, warnings: [], errors: [] }
}
private async optimizeModules(moduleGraph: ModuleGraph): Promise<ModuleNode[]> {
const modules = Array.from(moduleGraph.modules.values())
// 应用插件转换
for (const module of modules) {
if (module.transformResult) {
const result = await this.pluginContainer.transform(
module.transformResult.code,
module.id
)
if (result) {
module.transformResult = result
}
}
}
return modules
}
private splitChunks(modules: ModuleNode[]): Chunk[] {
const chunks: Map<string, Chunk> = new Map()
// 识别共享依赖
const sharedDeps = this.findSharedDependencies(modules)
// 按配置生成代码分割
const manualChunksConfig = {
'vendor-react': ['react', 'react-dom'],
'vendor-ui': ['antd']
}
Object.entries(manualChunksConfig).forEach(([chunkName, depNames]) => {
const chunkModules = modules.filter(mod =>
depNames.some(dep => mod.id.includes(dep))
)
chunks.set(chunkName, {
name: chunkName,
modules: chunkModules,
fileName: `${chunkName}.js`
})
})
return Array.from(chunks.values())
}
private async minifyChunks(chunks: Chunk[]): Promise<MinifyResult[]> {
const results: MinifyResult[] = []
for (const chunk of chunks) {
const code = this.generateChunkCode(chunk)
// 使用 terser 进行压缩
const minified = await terser.minify(code, {
compress: {
drop_console: true,
pure_funcs: ['console.log', 'console.info']
},
mangle: {
toplevel: true,
properties: {
regex: /^_/
}
}
})
if (minified.code) {
results.push({
chunkName: chunk.name,
code: minified.code,
map: minified.map
})
}
}
return results
}
}
```
## 性能优化机制
### 缓存策略
```mermaid
graph TD
A[请求模块] --> B{缓存检查}
B -->|内存缓存命中| C[返回缓存]
B -->|磁盘缓存命中| D[加载并返回]
B -->|缓存未命中| E[编译模块]
E --> F[写入缓存]
F --> C
```
### 多层缓存实现
```typescript
class CacheSystem {
private memoryCache = new Map<string, CacheEntry>()
private diskCache: DiskCache
private etagCache = new Map<string, string>()
async get(key: string): Promise<string | null> {
// 1. 检查内存缓存
const memEntry = this.memoryCache.get(key)
if (memEntry && !this.isExpired(memEntry)) {
return memEntry.content
}
// 2. 检查磁盘缓存
try {
const diskEntry = await this.diskCache.get(key)
if (diskEntry) {
// 写入内存缓存
this.memoryCache.set(key, {
content: diskEntry.content,
etag: diskEntry.etag,
timestamp: Date.now()
})
return diskEntry.content
}
} catch (e) {
// 缓存损坏,忽略
}
return null
}
async set(key: string, content: string, options: CacheOptions = {}): Promise<void> {
const etag = this.generateETag(content)
const entry: CacheEntry = {
content,
etag,
timestamp: Date.now(),
ttl: options.ttl || 0
}
// 写入内存缓存
this.memoryCache.set(key, entry)
// 持久化到磁盘
if (options.persistent) {
await this.diskCache.set(key, {
content,
etag
})
}
}
private generateETag(content: string): string {
const hash = crypto.createHash('sha1')
hash.update(content)
return hash.digest('hex')
}
private isExpired(entry: CacheEntry): boolean {
if (entry.ttl === 0) return false
return Date.now() - entry.timestamp > entry.ttl
}
}
```
### HTTP 缓存优化
```typescript
class HTTPCacheManager {
setupCacheHeaders(res: ServerResponse, content: string): void {
const etag = this.generateETag(content)
const lastModified = new Date().toUTCString()
// 设置缓存头
res.setHeader('Cache-Control', 'public, max-age=31536000, immutable')
res.setHeader('ETag', etag)
res.setHeader('Last-Modified', lastModified)
// 检查客户端缓存
if (this.request) {
const ifNoneMatch = this.request.headers['if-none-match']
const ifModifiedSince = this.request.headers['if-modified-since']
if ((ifNoneMatch && ifNoneMatch === etag) ||
(ifModifiedSince && ifModifiedSince === lastModified)) {
res.statusCode = 304
res.end()
return true
}
}
return false
}
}
```
## 进阶架构特性
### 虚拟模块系统
```typescript
// 虚拟模块插件示例
export function virtualModulePlugin(): Plugin {
return {
name: 'virtual-module',
resolveId(id) {
if (id === 'virtual:env') {
return '\0virtual:env'
}
},
load(id) {
if (id === '\0virtual:env') {
const env = {
NODE_ENV: process.env.NODE_ENV,
VERSION: '1.0.0'
}
return `export default ${JSON.stringify(env)}`
}
}
}
}
// 使用虚拟模块
import env from 'virtual:env'
console.log(env) // { NODE_ENV: 'development', VERSION: '1.0.0' }
```
### Source Map 生成
```typescript
class SourceMapGenerator {
async generateSourceMap(
originalCode: string,
transformedCode: string,
filePath: string
): Promise<SourceMap> {
const sourceMap: SourceMap = {
version: 3,
file: path.basename(filePath),
sourceRoot: '',
sources: [filePath],
names: [],
mappings: ''
}
// 使用 magic-string 生成精确的 mappings
const magicString = new MagicString(originalCode)
const transformed = new MagicString(transformedCode)
// 映射转换的位置
const mappings = this.generateMappings(originalCode, transformedCode)
sourceMap.mappings = mappings
return sourceMap
}
private generateMappings(original: string, transformed: string): string {
// 使用 VLQ 编码生成 mappings
const originalLines = original.split('\n')
const transformedLines = transformed.split('\n')
const mappings: string[] = []
let currentLine = 0
let currentColumn = 0
for (let i = 0; i < transformedLines.length; i++) {
const lineMappings: number[][] = []
for (let j = 0; j < transformedLines[i].length; j++) {
// 找到原始代码中的对应位置
const { line, column } = this.findOriginalPosition(
transformedLines[i],
j,
originalLines
)
if (line !== -1) {
lineMappings.push([
j - currentColumn, // 生成的列偏移
line - currentLine, // 原始行偏移
column // 原始列
])
currentColumn = j
currentLine = line
}
}
// 使用 VLQ 编码
mappings.push(lineMappings.map(mapping =>
this.encodeVLQ(mapping)
).join(','))
currentLine = transformedLines.length
currentColumn = 0
}
return mappings.join(';')
}
}
```
## 架构对比
### 与传统构建工具对比
| 特性 | Vite | Webpack | Parcel |
|------|------|---------|--------|
| 启动原理 | ESM 按需编译 | 全量打包 | 零配置打包 |
| HMR 机制 | 模块级更新 | 全局重编译 | 智能更新 |
| 构建产出 | Rollup | 内置 | 内置 |
| 配置复杂度 | 低 | 高 | 极低 |
| 插件生态 | 新兴 | 成熟 | 有限 |
| 开发体验 | 优秀 | 可优化 | 良好 |
| 生产构建 | 高质量 | 高质量 | 良好 |
### 适用场景分析
```mermaid
graph TD
A[项目类型] --> B{选择构建工具}
B -->|React/Vue SPA| C[Vite 推荐]
B -->|复杂构建需求| D[Webpack]
B -->|零配置快速开发| E[Parcel]
B -->|Next.js SSR| F[Next.js 内置]
C --> G[👍 启动快<br/>👍 HMR 优秀<br/>👍 配置简单]
D --> H[👍 生态成熟<br/>👍 高度可定制<br/>👎 复杂]
E --> I[👍 开箱即用<br/>👍 智能配置<br/>👎 生态有限]
```
理解 Vite 的架构原理,不仅能帮助我们更好地使用它,还能为开发自定义插件和解决复杂问题提供理论支撑。Vite 的成功在于它巧妙地利用了现代浏览器和工具链的能力,选择了正确的技术路径。
相关文档:
- [[DEV/VITE/配置详解.md]] - 配置与插件开发
- [[DEV/VITE/优化实践.md]] - 架构层面的性能优化