面试题:Vite 在冷启动和热更新方面比 Webpack 更快的原因是什么

90 阅读2分钟

1. 冷启动更快的原因

// Webpack 的处理方式
// 需要先打包所有模块
webpack.config.js
{
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  }
}

// Vite 的处理方式
// 基于 ESM,按需加载
<script type="module">
  import { createApp } from 'vue'
  import App from './App.vue'
</script>

Webpack vs Vite:

  1. Webpack:
  • 需要先打包所有模块

  • 构建依赖图

  • 生成 bundle

  • 启动时间随项目大小增加

  1. Vite:
  • 利用浏览器原生 ESM 支持

  • 无需打包按需编译

  • 只编译当前页面需要的文件

  • 启动时间与项目大小关系小

2. 热更新更快的原因

// Webpack HMR
// 需要重新打包整个模块链
if (module.hot) {
  module.hot.accept('./component.js', function() {
    // 更新逻辑
  })
}

// Vite HMR
// 精确定位并替换单个模块
if (import.meta.hot) {
  import.meta.hot.accept((newModule) => {
    // 更新逻辑
  })
}

热更新比较:

  1. Webpack:

    // Webpack 热更新流程
    1. 改动文件
    2. 重新打包改动模块及其依赖
    3. 生成新的 chunk
    4. 通过 WebSocket 推送更新
    5. 客户端重新加载对应模块
    
  2. Vite:

    // Vite 热更新流程
    1. 改动文件
    2. 编译单个改动文件
    3. 通过 WebSocket 推送更新
    4. 浏览器直接重新请求该模块
    

3. 核心差异

// Webpack 开发服务器启动流程
1. 读取项目文件
2. AST 分析
3. 依赖收集
4. 模块转换
5. 代码打包
6. 启动服务器

// Vite 开发服务器启动流程
1. 启动服务器
2. 请求时按需编译

主要优势:

  1. 按需加载

    // Vite 只编译当前页面需要的文件
    import { foo } from './foo.js'  // 仅在需要时加载
    
  2. 预构建优化

    // vite.config.js
    export default defineConfig({
      optimizeDeps: {
        include: ['lodash-es']  // 预构建常用依赖
      }
    })
    
  3. 缓存机制

    // Vite 会缓存已编译的文件
    // 浏览器也会缓存 ESM 模块
    

4. 实际效果

// 项目规模对启动时间的影响
// Webpack
项目大小 ∝ 启动时间  // 启动时间与项目大小成正比

// Vite
项目大小 ≠ 启动时间  // 启动时间基本恒定

总结:

  • Vite 利用浏览器原生 ESM 能力

  • 采用按需编译而非全量打包

  • 更精确的热更新机制

  • 优秀的缓存策略

这些特性使得 Vite 在开发环境下能够提供更好的性能体验。