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+,因此拆包設定升級前要連同建置環境一起確認。
先保留預設,找出真正的大檔
先執行正式建置並看輸出大小:
pnpm vite buildVite 的 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,可以用 test 和 name 描述要分組的模組。若目標是把確認過的編輯器套件維持在獨立 chunk,可以從這種設定開始:
import { defineConfig } from 'vite'
export default defineConfig({ build: { rolldownOptions: { output: { codeSplitting: { groups: [ { test: /node_modules[\\/]monaco-editor[\\/]/, name: 'editor', }, ], }, }, }, },})codeSplitting 是更適合表達分組規則的 Rolldown 選項,但不是「設定後一定更快」的按鈕。分組會影響快取、平行下載、模組執行順序和 runtime chunk;先用一個低頻、體積明確的依賴驗證,再決定是否擴大範圍。
三個容易漏掉的風險
- 手動分組可能讓相依項目一併進入 chunk,結果比預期更大。
- 改變 chunk 邊界可能讓有 side effect 的模組提早執行,進而改變應用程式行為。
codeSplitting也可能改變快取和 runtime 載入順序,必須測試首次進入、延遲頁面與舊 HTML 載入新 chunk 的情況。
因此每次調整後都應測兩件事:首次進入主要頁面的 network waterfall,以及進入延遲功能時是否仍會正確載入。若有 deploy 後舊頁面載不到動態 chunk,可監聽 Vite 的 vite:preloadError,並確認 HTML 的快取策略不會長期引用已刪除的舊檔名。
升級 Vite 8 時順手盤點的設定
Vite 8 會用相容層轉換部分舊設定,但相容不等於未來不會移除。可以先用這張表盤點:
| 舊設定或行為 | Vite 8 的方向 | 這次要做什麼 |
|---|---|---|
build.rollupOptions | build.rolldownOptions 的 deprecated alias | 新增或修改設定時使用 rolldownOptions |
output.manualChunks object form | 不再支援 | 改成 codeSplitting.groups 或保留 function form 的短期相容路徑 |
output.manualChunks function form | deprecated | 量測後逐步改成 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。
參考資料:
回報錯字、失效連結,或告訴我你想看的延伸主題。