工程化知識卡片 010: Javascript 程式碼壓縮 (minify) 的原理是什麼

語言: CN / TW / HK

小知識,大挑戰!本文正在參與“程式設計師必備小知識”創作活動。

大家好,我是山月。

這是我在掘金髮表的前端工程化知識卡片集合 10/36


通過 AST 分析,根據一些策略,來生成一顆更小體積的 AST 並生成程式碼。目前前端工程化中使用 terser 進行 JS 程式碼壓縮。

常見用以壓縮 AST 的幾種方案如下:

去除多餘字元: 空格,換行及註釋

javascript // 對兩個數求和 function sum (a, b) { return a + b; }

此時檔案大小是 62 Byte一般來說中文會佔用更大的空間。

多餘的空白字元會佔用大量的體積,如空格,換行符,另外註釋也會佔用檔案體積。當我們把所有的空白符合註釋都去掉之後,程式碼體積會得到減少。

去掉多餘字元之後,檔案大小已經變為 30 Byte 壓縮後代碼如下:

javascript function sum(a,b){return a+b}

替換掉多餘字元後會有什麼問題產生呢?

有,比如多行程式碼壓縮到一行時要注意行尾分號。

壓縮變數名:變數名,函式名及屬性名

javascript function sum (first, second) { return first + second; }

如以上 firstsecond 在函式的作用域中,在作用域外不會引用它,此時可以讓它們的變數名稱更短。但是如果這是一個 module 中,sum 這個函式也不會被匯出呢?那可以把這個函式名也縮短。

``` javascript // 壓縮: 縮短變數名 function sum (x, y) { return x + y;
}

// 再壓縮: 去除空餘字元 function s(x,y){return x+y} ```

在這個示例中,當完成程式碼壓縮 (compress) 時,程式碼的混淆 (mangle) 也捎帶完成。 但此時縮短變數的命名也需要 AST 支援,不至於在作用域中造成命名衝突。

解析程式邏輯:合併宣告以及布林值簡化

通過分析程式碼邏輯,可對程式碼改寫為更精簡的形式。

合併宣告的示例如下:

``` javascript // 壓縮前 const a = 3; const b = 4;

// 壓縮後 const a = 3, b = 4; ```

布林值簡化的示例如下:

``` javascript // 壓縮前 !b && !c && !d && !e

// 壓縮後 !(b||c||d||e) ```

解析程式邏輯: 編譯預計算

在編譯期進行計算,減少執行時的計算量,如下示例:

``` javascript // 壓縮前 const ONE_YEAR = 365 * 24 * 60 * 60

// 壓縮後 const ONE_YAAR = 31536000 ```

以及一個更復雜的例子,簡直是殺手鐗級別的優化。

``` javascript // 壓縮前 function hello () { console.log('hello, world') }

hello()

// 壓縮後 console.log('hello, world') ```