JavaScript 壓縮的運作原理
Terser 對你程式碼的抽象語法樹(AST)分四個階段處理。每個階段都是獨立的,因此你可以單獨開啟或關閉任何階段,而不影響其他階段。
- 解析. Terser 將你的 JavaScript 解析為 AST。任何語法錯誤都會在此顯示,並附上造成錯誤的 token 和行號,讓你在任何轉換執行前就找到真正的問題。解析器接受最新 stage-4 提案以內的所有標準 ECMAScript 構造。
- 壓縮. 壓縮器走訪 AST 並套用數十種保留語意的轉換:常數折疊、死分支消除、短純函式內聯、合併連續的
var宣告,以及改寫等效敘述形式(if/else轉為三元運算子、比較鏈縮短、條件式 return 折疊)。每個轉換在原則上都是可逆的;壓縮器絕不改變可觀察到的行為。 - 混淆. 混淆器在每個作用域內將本地綁定重新命名為最短的唯一識別碼(
a、b、c……)。只有無法逃脫模組邊界的名稱才會被重新命名,因此匯出的綁定、屬性鍵和全域引用保持不變。這是所有階段中單次節省位元組最多的步驟。 - 輸出. Terser 將轉換後的 AST 重新輸出為 JavaScript 字串,並折疊空白,將敘述分隔符縮減至語法允許的最小值。注釋會被移除,除非保留授權注釋切換保留了
/*! … */區塊,大多數 CDN 授權要求保留這些區塊。
為什麼要壓縮 JavaScript?
- 更快的頁面載入. 更小的腳本解析和執行更快。在 4G 行動網路上,40% 的位元組縮減能顯著縮短 Time to Interactive,而這正是 Google PageSpeed Insights 最積極衡量的指標。
- 更低的 CDN 出網費用. CloudFront、Cloudflare 和 Fastly 均按每 GB 出網流量計費。每月數百萬次頁面瀏覽中腳本減少 40%,在任何圖片或 CSS 優化到位之前就已形成真實節省。即使在 gzip 和 brotli 壓縮之後,這個數字依然成立——壓縮消除了壓縮演算法原本必須編碼的 token。
- 此壓縮器不拖慢你的頁面. Terser 未壓縮約 1 MB。大多數線上壓縮器在頁面載入時就傳送整個函式庫,這會拖累它們自己的 Lighthouse 分數,並讓使用者輸入前頁面感覺遲緩。此頁面只在你點擊「壓縮」或開啟即時模式時才延遲載入 Terser——因此初始渲染維持在 Core Web Vitals 門檻之下,而這正是此工具承諾幫你達到的目標。
- 通過 Core Web Vitals. Lighthouse 和 PageSpeed Insights 將過大的 JavaScript 標記為 Total Blocking Time 不良的直接原因。壓縮供應商函式庫和應用程式 bundle 是 Lighthouse「減少未使用的 JavaScript」與「移除重複模組」稽核項目上最快的優化方式——通常是一次性減少十至二十分的機會。
常見應用場景
JavaScript 壓縮幾乎出現在現代 Web 專案的每個階段。
- pre-commit hook:在提交到 repo 前壓縮個別工具腳本,使提交的產出物即為正式環境就緒的版本,且 diff 顯示的是邏輯變更而非空白雜訊。
- 第三方 widget 稽核:貼上供應商的嵌入程式碼片段,檢查它是否已壓縮,或在服務數百萬使用者前是否還能進一步縮小。
- 舊式腳本清理:壓縮早於目前建置流程的 jQuery 外掛和手工撰寫的腳本,而無需觸及原始碼樹。
實際操作範例
取一個小型函式:function add(firstNumber, secondNumber) { /* sums two numbers */ return firstNumber + secondNumber; } console.log(add(1, 2));——含注釋約 130 位元組。同時開啟混淆和壓縮後貼入上方。輸出縮短至大約 function add(n,o){return n+o}console.log(add(1,2));——約 55 位元組,減少 58%。函式名稱 add 保留,因為它在 console.log 呼叫中被引用;參數名稱 firstNumber 和 secondNumber 縮短為單字母,因為它們是函式體內的本地變數。關閉混淆可在仍折疊空白並去除注釋的同時保留可讀的參數名稱。
FAQ
這在我的瀏覽器中執行嗎?
是的。Terser 在你第一次點擊「壓縮」或啟用即時模式時延遲載入——約 200 KB 壓縮後的內容進入你的瀏覽器快取,之後不再下載。你的程式碼不會離開頁面。
什麼是名稱混淆,它安全嗎?
混淆會將本地變數重新命名為單字母以節省位元組。對於自包含的腳本和 IIFE bundle 是安全的,因為重新命名不會超出作用域。對於以名稱將全域暴露的腳本(例如沒有包裝器的 window.myLib = …)則不安全。不確定時請關閉混淆。
壓縮後我的程式碼為什麼出現問題?
三個常見原因:eval 或 with 以字串引用變數;Function.name 或 arguments.callee 讀取依賴原始識別碼;或以被重新命名的名稱暴露的全域。先關閉混淆,以確認是重新命名還是壓縮轉換造成問題。
支援現代語法(ES2020+)嗎?
是的。將 ECMAScript 目標設為 ES2020 或最新,Terser 會保留可選鏈、空值合併運算子、頂層 await 和邏輯賦值運算子。設為 ES5 時,Terser 在可能的情況下會向下編譯,但它不是完整的 transpiler——對 ES5 根本無法表示的語法請使用 Babel。
在瀏覽器端使用 Terser 壓縮 JavaScript,可獲得生產品質的輸出而無需增加建置工具。貼上腳本、選擇 ECMAScript 目標版本、複製或下載結果。無需上傳、無需帳號、無需建置流程。壓縮器本身只在你要求時才載入——因此開啟此頁面只需花費幾 KB,而非一 MB。