Skip to content

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. 生态集成

  • 与主流框架集成
  • 与主流工具集成
  • 与主流服务集成

性能优化

开发环境优化

  1. 缓存策略

    • 文件系统缓存
    • 转换结果缓存
    • 依赖预构建缓存
  2. 按需编译

    • 只编译访问的文件
    • 延迟编译未访问的文件
  3. 增量更新

    • 只更新修改的模块
    • 复用未修改的模块

生产环境优化

  1. 代码分割

    • 路由级别分割
    • 组件级别分割
    • 动态导入
  2. Tree-shaking

    • 移除未使用的代码
    • 优化依赖树
  3. 资源优化

    • 压缩
    • 哈希命名
    • CDN 加速

总结

Vite 的架构设计充分利用了现代浏览器的能力,通过 ES 模块和按需编译实现了极速的开发体验。同时,通过 Rollup 和各种优化技术,保证了生产环境的性能和优化。插件系统提供了强大的扩展能力,使得 Vite 能够适应各种不同的应用场景。

架构师AI杜公众号二维码

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