Skip to content
⚠️ This article was written in 2020. Some content may be outdated.

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 server | Vite | | ---------- | ---------------------- | -------------- | | 冷啟動 | 慢(需要打包所有模組) | 快(按需轉換) | | HMR 速度 | 毫秒~秒(依專案大小) | 始終毫秒級 | | 生產構建 | webpack | Rollup | | 配置複雜度 | 高 | 低 | | 相容性 | 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