JavaScript 打包器(module bundler)介紹|運作原理與優點
更新日期: 2024 年 11 月 16 日
在現代 JavaScript 開發中,模組化設計已成為標準做法。
我們經常使用像 import x from "dayjs";
的語法來引用第三方模組。
然而,直接使用這種語法時常會報錯:
Uncaught TypeError: Failed to resolve module specifier "dayjs". Relative references must start with either "/", "./", or "../".
這類錯誤表示 JavaScript 模組,需要使用相對或絕對路徑來引用資源。
例如 ./node_modules/dayjs/dayjs.min.js
,而直接使用 "dayjs"
會被認為是無效路徑。
雖然可以手動找到 node_modules
資料夾中的正確路徑來引用,但這樣做既麻煩又容易出錯。
因此,我們通常會使用「打包器」來簡化模組管理流程,並提升開發效率。
建議閱讀本文前,具備相關概念:
什麼是打包器?
打包器(如 Webpack、Parcel、Esbuild、Bun、Vite 等)是將多個 JavaScript、CSS、圖片等資源合併為單一檔案的工具。
打包器的主要目的是將程式中多檔案、多模組的結構統一打包成單一或少量幾個檔案,以便於佈署和管理。
通過打包器,開發者不僅可以有效解決模組引用的路徑問題,還可以優化程式碼、減少請求次數、管理快取等。
打包器的主要功能
- 合併文件:將多個 JavaScript、CSS 檔案合併為單一檔案。
- Tree Shaking:自動移除未使用的代碼,減少最終打包的檔案大小。
- 快取管理:生成帶有版本號的檔案,避免快取問題。
- 文件壓縮:通過壓縮代碼減少檔案體積,提升載入速度。
為什麼需要打包器?
打包器的好處,在於它能夠優化網站載入速度,並管理多檔案模組的引用問題,特別是以下幾個方面的優勢:
優點 1:Tree Shaking 與代碼優化
Tree Shaking 是指在打包過程中移除未使用的代碼。
例如,假設在程式中定義了一個變數 var ajijiji = 888;
,但該變數從未使用過,打包器就會自動將這段代碼移除。
此外,打包器也會優化變數名稱,比如將 ajijiji
簡化為 n
,從而縮小檔案體積。
// 原始代碼
var ajijiji = 888;
// 優化後的代碼
var n = 888;
未使用的變數和函數會被完全刪除,減少了最終輸出的檔案大小。
這樣的代碼優化在大型專案中特別有效,能顯著縮減檔案大小。
優點 2:快取管理
當我們在網站上載入 JavaScript 檔案時,瀏覽器會自動對這些資源進行快取。
這意味著,如果檔案沒有變動,瀏覽器會從快取中加載檔案,而不是重新從伺服器獲取。
但如果檔案有更新,而瀏覽器的快取仍然保存舊檔案,則可能會導致程式出錯。
在傳統方法中,我們通常會在 <script>
標籤後加上時間戳,來強制瀏覽器刷新快取:
<script src="main.js?t=時間"></script>
使用打包器後,每次打包時會自動生成帶有唯一編號的檔案名稱(如 index-xxxx.js
)。
當檔案內容變動時,檔案編號也會隨之更新,瀏覽器會認為是新檔案,從而重新載入。
這樣,我們不再需要手動處理快取問題。
<script src="index-編號.js" type="module"></script>
優點 3:減少 HTTP 請求數量(適用於 HTTP/1.1)
在 HTTP/1.1 下,每個檔案的下載請求都需要經過一次握手(handshake),過多的 HTTP 請求會增加網路延遲。
打包器能將多個 JavaScript 或 CSS 檔案合併為一個檔案,從而減少握手次數並縮短載入時間。
但在 HTTP/2 環境下,打包的重要性相對降低,因為 HTTP/2 支援多路複用,可以在一次握手後同時載入多個檔案。
因此,對於 HTTP/2 環境,將過多檔案合併為一個不再是最佳策略。
優點 4:支援多種資源類型
打包器除了可以處理 JavaScript 外,還可以處理 CSS、圖片、字型等資源,並將這些資源整合到最終的打包檔案中,形成完整的應用程式。
這樣,不同類型的資源,可以一同打包並進行版本管理,使佈署流程更加簡單。
案例:使用 Vite 打包器進行快速開發
Vite 是一款輕量級、高效能的打包器,專為現代化 JavaScript 開發而設計。
Vite 利用原生 ES 模組支持,避免了傳統打包器在開發階段的繁瑣步驟,因此它可以顯著縮短開發伺服器的啟動時間和模組加載時間。
這對於依賴大量模組的大型專案尤其有用。
安裝 Vite
要使用 Vite,首先需要將其安裝到專案中。使用以下指令安裝 Vite,並將其作為開發依賴:
npm install -D vite
-D
選項表示將 Vite 安裝為開發依賴,僅在開發環境中使用,而佈署到線上環境時不包含此依賴。
設定 Vite 專案結構
安裝完成後,我們可以創建一個基本的 index.html
作為專案的入口頁面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hello Vite</title>
</head>
<body>
<p>Hello Vite!</p>
<script src="main.js" type="module"></script>
</body>
</html>
Vite 會自動偵測 index.html
中的 JavaScript 模組並處理其依賴關係。
使用 Vite 的 CLI 指令
在 package.json
中,可以新增 NPM 腳本指令來啟動 Vite 伺服器,執行各種開發和打包任務:
{
"scripts": {
"dev": "vite", // 啟動開發伺服器
"build": "vite build", // 打包專案
"preview": "vite preview" // 預覽打包結果
},
"dependencies": {
"axios": "^1.7.7",
"dayjs": "^1.11.13",
"vite": "^5.4.10"
}
}
執行以下指令來啟動開發伺服器:
npm run dev
啟動後,終端機會顯示 Vite 的啟動訊息,並提供本地伺服器網址:
VITE v5.4.10 ready in 119 ms
➜ Local: http://localhost:5173/
此時,進入 http://localhost:5173/
,我們便能看到頁面內容。
點擊打包好的 main.js
檔案,可以確認 Vite 已經自動解決了 import dayjs
的模組路徑問題,無需手動指定 node_modules
的路徑。
Vite 的快取管理與靜態資源優化
Vite 在每次打包後,會自動生成帶有版本編號的檔案,例如 index-xxxx.js
。每次檔案
內容變動後,檔案的 hash 值也會跟著改變,瀏覽器會因此重新載入新檔案,而不再依賴舊快取。
這大幅簡化了版本管理問題,讓開發和佈署更加便捷。
此外,Vite 還支援壓縮輸出文件,從而優化檔案大小和傳輸速度。
這些功能讓 Vite 不僅適合開發環境,也非常適合用於生產環境的佈署。
總結
打包器的引入顯著提升了 JavaScript 開發的效率與模組管理的便利性。
通過打包器,我們可以將多個模組、資源整合並壓縮成少數檔案,解決模組引入路徑、資源快取、HTTP 請求優化等問題。
Vite 作為新一代打包工具,專注於提升開發體驗和效能,是現代前端開發的理想選擇。
重點回顧
- 打包器的作用:解決模組管理、資源合併、快取優化等問題。
- Tree Shaking:自動移除未使用的代碼,減少最終檔案大小。
- Cache Busting:生成帶有版本號的檔案名,解決瀏覽器快取問題。
- 效能提升:在 HTTP/1.1 環境中減少請求次數,提高載入速度。
- Vite 的優勢:使用原生 ES 模組支持,提升開發伺服器的啟動和模組加載速度,特別適合大型項目。
通過合理使用打包器,開發者可以顯著簡化模組管理流程,並提高程式碼的可維護性和載入速度。