1299 字
6 分鐘

Vite 8 拆包怎麼設?manualChunks 逐步轉向 Rolldown codeSplitting

看到初始 JavaScript 變大時,很多人會立刻在 Vite 加一個 manualChunks(),把所有 node_modules 收進 vendor。這不是預設安全的效能修正:拆包會改變模組的載入時機與快取邊界,過度手動分組也可能把本來不需一開始下載的程式碼提前載入。

直接答案是:先量測目前產物與進入點,再只為可辨識的重型、低頻或共用模組建立 chunk;升級到 Vite 8 後,先把 build.rollupOptions 盤點成 build.rolldownOptions,再評估是否用 output.codeSplitting 取代長期依賴 manualChunks

Vite 8 使用 Rolldown 和 Oxc 取代原本的 Rollup、esbuild 組合;官方 migration guide 也把 output.manualChunks 的 object form 列為不再支援,function form 則標為 deprecated。Vite 8 的 Node.js 需求是 20.19+ 或 22.12+,因此拆包設定升級前要連同建置環境一起確認。

先保留預設,找出真正的大檔#

先執行正式建置並看輸出大小:

Terminal window
pnpm vite build

Vite 的 production build 會產生適合靜態託管的 bundle。若路由或動態 import 已把低頻功能分開,新增 manualChunks 不一定有益;先找出哪個 entry、依賴或共同模組讓初始路徑變大,再決定是否介入。

manualChunks 還能用,但先知道它的定位#

在 Vite 8 裡,manualChunks 的 function form 仍可作為相容路徑,但已不是長期設定方向;object form 不再支援。若暫時需要保留既有規則,至少把底層設定名稱改成 rolldownOptions,並用明確的 module id 判斷:

import { defineConfig } from 'vite'
export default defineConfig({
build: {
rolldownOptions: {
output: {
// 相容路徑:只用在已量測的重型、低頻功能
manualChunks(id) {
if (id.includes('/node_modules/monaco-editor/')) {
return 'editor'
}
},
},
},
},
})

這能讓只有進入編輯器的使用者才下載 editor chunk;但不要用 package 名稱的模糊比對,也不要假設所有第三方套件都該集中成 vendor。檢查實際 resolved id,避免 foo 意外命中 foo-utils。函式形式也可能連同相依項目一起被納入,因此每次都要檢查實際輸出,而不是只看設定檔。

Vite 8 的長期路徑:改用 codeSplitting#

Rolldown 提供更明確的 output.codeSplitting.groups,可以用 testname 描述要分組的模組。若目標是把確認過的編輯器套件維持在獨立 chunk,可以從這種設定開始:

import { defineConfig } from 'vite'
export default defineConfig({
build: {
rolldownOptions: {
output: {
codeSplitting: {
groups: [
{
test: /node_modules[\\/]monaco-editor[\\/]/,
name: 'editor',
},
],
},
},
},
},
})

codeSplitting 是更適合表達分組規則的 Rolldown 選項,但不是「設定後一定更快」的按鈕。分組會影響快取、平行下載、模組執行順序和 runtime chunk;先用一個低頻、體積明確的依賴驗證,再決定是否擴大範圍。

三個容易漏掉的風險#

  1. 手動分組可能讓相依項目一併進入 chunk,結果比預期更大。
  2. 改變 chunk 邊界可能讓有 side effect 的模組提早執行,進而改變應用程式行為。
  3. codeSplitting 也可能改變快取和 runtime 載入順序,必須測試首次進入、延遲頁面與舊 HTML 載入新 chunk 的情況。

因此每次調整後都應測兩件事:首次進入主要頁面的 network waterfall,以及進入延遲功能時是否仍會正確載入。若有 deploy 後舊頁面載不到動態 chunk,可監聽 Vite 的 vite:preloadError,並確認 HTML 的快取策略不會長期引用已刪除的舊檔名。

升級 Vite 8 時順手盤點的設定#

Vite 8 會用相容層轉換部分舊設定,但相容不等於未來不會移除。可以先用這張表盤點:

舊設定或行為Vite 8 的方向這次要做什麼
build.rollupOptionsbuild.rolldownOptions 的 deprecated alias新增或修改設定時使用 rolldownOptions
output.manualChunks object form不再支援改成 codeSplitting.groups 或保留 function form 的短期相容路徑
output.manualChunks function formdeprecated量測後逐步改成 codeSplitting
optimizeDeps.esbuildOptions由相容層轉成 Rolldown 選項,並標示 deprecated有自訂依賴預打包時改查 optimizeDeps.rolldownOptions
build.minify: 'esbuild'deprecated只有確定需要時才保留,並測試 Oxc minifier 的差異

不要因為設定名稱換了就期待 bundle 自動變小;先建置、記錄輸出和主要入口的 waterfall,再逐項切換。若你的專案還同時處理前端環境變數,也可以參考 Vite .env 的前端金鑰邊界 把建置設定與 secret 風險分開。

一個可重複的拆包流程#

先以預設設定建置,再用 bundle 視覺化或瀏覽器 network 資料找出具體問題;只為一個明確的載入路徑新增規則;重新建置並測試入口與延遲頁;最後把「為何拆、如何驗證」記錄在設定旁。這比維護一串例外套件名更容易在下次依賴升級時判斷是否仍需要。

升級到 Vite 8 時,再多做兩項檢查:建置機的 Node.js 是否符合 20.19+ 或 22.12+,以及 production 與本機的 chunk 輸出是否使用同一套設定。只在本機開發頁面正常,不代表部署後的快取、CDN 或舊 HTML 也能載到正確 chunk。

參考資料:

Vite Docs:Building for Production

Vite Docs:Migration from v7

Vite Docs:Build Options

Vite Blog:Vite 8

Rolldown:Manual Code Splitting

Vite 8 拆包怎麼設?manualChunks 逐步轉向 Rolldown codeSplitting
https://laplusda.com/posts/optimize-vite-build-with-custom-chunking/
作者
Zero
發佈於
2024-08-27
許可協議
CC BY-NC-SA 4.0
這篇文章有幫助嗎?

回報錯字、失效連結,或告訴我你想看的延伸主題。