Skip to content

Vite 开发服务器原理:基于 ESM 的极速热更新

Vite 1.0 在 2020 年发布后,"秒级启动"让很多人惊叹。本文深入分析 Vite 能做到这一点的底层原理,以及它和 webpack dev server 的根本区别。

传统 webpack 的瓶颈

webpack 在启动时必须先打包再服务

启动 webpack dev server:
1. 解析所有入口和依赖树(可能几千个模块)
2. 转换每个模块(TS→JS、Less→CSS 等)
3. 将所有模块打包成 bundle
4. 启动 HTTP 服务,提供 bundle
→ 冷启动时间:几十秒到几分钟(大型项目)

这意味着你改一个文件,webpack 需要重新构建受影响的整个 chunk,然后通过 WebSocket 发送更新。

Vite 的 No-bundle 方案

启动 Vite dev server:
1. 仅预构建 node_modules 中的依赖(esbuild,极快)
2. 启动 HTTP 服务
→ 冷启动时间:< 1 秒

浏览器请求页面时:
按需转换被请求的模块(而不是提前打包所有模块)

这依赖于现代浏览器原生支持 ES Module:

html
<!-- index.html -->
<script type="module" src="/src/main.ts"></script>

浏览器看到 type="module" 后,会自行解析 import 语句并发起请求。Vite 只需要在服务端转换被请求的文件:

javascript
// 浏览器请求 /src/App.vue
// Vite 服务端接收请求,实时转换:
// 1. 解析 .vue 文件的 template、script、style
// 2. 将 template 编译成 render function
// 3. 返回 ES module 格式的 JS

依赖预构建

node_modules 中的包通常是 CommonJS 格式,浏览器不能直接 import。Vite 在首次启动时用 esbuild 预构建这些依赖:

# Vite 启动时的预构建
node_modules/lodash-es → .vite/lodash-es.js  (合并成单文件,减少请求数)
node_modules/vue       → .vite/vue.js
...

esbuild 是 Go 语言编写的打包工具,速度比 webpack 快 10-100 倍,所以这个步骤通常在几百毫秒内完成。

HMR 实现原理

Vite 的 HMR 比 webpack 更精准:

javascript
// Vite HMR 协议
// 当 src/components/Button.vue 被修改时:
// 1. Vite 文件监听器检测到变化
// 2. 分析该文件的 HMR 边界
// 3. 仅使这个文件的模块缓存失效
// 4. 通过 WebSocket 通知浏览器
// 5. 浏览器重新请求这个文件(而不是整个 bundle)

// 组件内接收 HMR
if (import.meta.hot) {
  import.meta.hot.accept("./Button.vue", (newModule) => {
    // 替换模块
  });
}

Vue 和 React 的 HMR 插件(@vitejs/plugin-vue@vitejs/plugin-react)自动处理组件级热更新,开发者通常不需要手写上面的代码。

与 webpack 的对比

webpack dev serverVite
冷启动慢(需要打包所有模块)快(按需转换)
HMR 速度毫秒~秒(依项目大小)始终毫秒级
生产构建webpackRollup
配置复杂度
兼容性IE11+现代浏览器

vite.config.js 基础配置

javascript
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

export default defineConfig({
  plugins: [vue()],
  server: {
    port: 3000,
    proxy: {
      "/api": {
        target: "http://localhost:8080",
        changeOrigin: true,
      },
    },
  },
  resolve: {
    alias: { "@": "/src" },
  },
});

总结

Vite 的快不是优化了 webpack,而是绕过了打包这一步。利用浏览器原生 ESM + esbuild 预构建,将"先打包再服务"变成了"按需转换"。这个思路对于理解下一代前端工具链非常重要。

MIT Licensed