本程式碼研究室會探討如何壓縮及壓縮下列應用程式的 JavaScript 套件,藉由縮減應用程式的要求大小,進而改善頁面效能。
測量
著手新增最佳化項目之前,最好先分析應用程式的目前狀態。
- 如要預覽網站,請按下「View App」,然後按下「Fullscreen」。
這個應用程式也包含在「移除未使用的程式碼」程式碼研究室中,可讓您投票選出喜愛的小貓。🐈
現在來看看這個應用程式的大小:
- 按下 Control+Shift+J 鍵 (或在 Mac 上為 Command+Option+J 鍵) 開啟開發人員工具。
- 按一下 [網路] 分頁標籤。
- 勾選「停用快取」核取方塊。
- 重新載入應用程式。
雖然在「移除未使用的程式碼」程式碼研究室中,為了縮減這個套件大小而完成許多進度,但 225 KB 仍然是很大的。
壓縮
請考慮使用以下程式碼區塊。
function soNice() {
let counter = 0;
while (counter < 100) {
console.log('nice');
counter++;
}
}
如果這個函式單獨儲存在檔案中,則檔案大小約為 112 B (位元組)。
如果移除所有空白字元,產生的程式碼如下所示:
function soNice(){let counter=0;while(counter<100){console.log("nice");counter++;}}
檔案大小現在約為 83 B。如果因縮減變數名稱長度並修改某些運算式而進一步破壞,最終程式碼最終可能會如下所示:
function soNice(){for(let i=0;i<100;)console.log("nice"),i++}
檔案大小現在達到 62 B。
每加入一個步驟,程式碼就會越難閱讀。不過,瀏覽器的 JavaScript 引擎會以完全相同的方式解讀這些函式。以這種方式模糊處理程式碼的優點有助於縮減檔案大小。112 B 的開端真的沒什麼好,但是大小仍減少了 50%!
在這個應用程式中,webpack 4 版會做為模組封裝器使用。您可以在 package.json
中查看特定版本。
"devDependencies": {
//...
"webpack": "^4.16.4",
//...
}
第 4 版已在實際工作環境模式中預設壓縮套件。這會使用 Terser 的 TerserWebpackPlugin
外掛程式。Terser 是用來壓縮 JavaScript 程式碼的熱門工具。
如要瞭解經過壓縮的程式碼,請在開發人員工具的「Network」面板中按一下 main.bundle.js
。現在,按一下「Response」分頁標籤。
最終格式的程式碼會經過壓縮並破壞,顯示在回應主體中。如要確認未壓縮的套件大小,請開啟 webpack.config.js
並更新 mode
設定。
module.exports = {
mode: 'production',
mode: 'none',
//...
重新載入應用程式,並透過開發人員工具的「Network」面板再次查看套件大小
比以前有點不同!😅
繼續操作前,請務必先還原這裡的變更。
module.exports = {
mode: 'production',
mode: 'none',
//...
在應用程式中加入壓縮程式碼的程序取決於您使用的工具:
- 如果使用 webpack v4 以上版本,由於程式碼在實際工作環境模式中預設為壓縮,因此不必執行其他作業。👍
- 如果使用的是舊版 Webpack,請在 Webpack 建構程序中安裝
TerserWebpackPlugin
。如需詳細說明,請參閱說明文件。 - 此外,您也可以使用其他壓縮外掛程式,例如 BabelMinifyWebpackPlugin 和 ClosureCompilerPlugin。
- 如果完全沒有使用模組組合工具,請使用 Terser 做為 CLI 工具,或直接將其納入為依附元件。
壓縮
雖然「壓縮」這個詞有時會略為用於說明壓縮過程中程式碼的減少方式,但實際上,這並非以常值為壓縮的方式。
壓縮通常是指使用資料壓縮演算法修改的程式碼。壓縮後通常會提供完全有效的程式碼,但壓縮程式碼必須在使用前進行解壓縮,才能使用。
針對每個 HTTP 要求和回應,瀏覽器和網路伺服器可以新增「標頭」headers,以納入有關擷取或接收資產的其他資訊。您可以在開發人員工具「Network」面板的「Headers
」分頁中看到下列三種類型:
- 「General」代表與整個要求/回應互動相關的一般標頭。
- 回應標頭會顯示來自伺服器實際回應的專屬標頭清單。
- 「Request Headers」(要求標頭) 會顯示用戶端附加至要求的標頭清單。
查看 Request Headers
中的 accept-encoding
標頭。
瀏覽器會使用 accept-encoding
指定其支援的內容編碼格式 (或壓縮演算法)。那裡有許多文字壓縮演算法,但這裡只有三種支援 HTTP 網路要求的壓縮 (及解壓縮) 演算法:
- Gzip (
gzip
):最常用於伺服器和用戶端互動的壓縮格式。以「防禦」演算法為基礎,且所有目前的瀏覽器都支援此功能。 - 延遲 (
deflate
):不常用。 - Brotli (
br
):新的壓縮演算法可進一步改善壓縮率,因此能加快頁面載入速度。多數瀏覽器皆支援這項功能。
本教學課程中的範例應用程式與「移除未使用的程式碼」程式碼研究室中完成的應用程式相同,唯一差別在於 Express 現已做為伺服器架構使用。後續章節將介紹靜態和動態壓縮。
動態壓縮
「動態」壓縮是指在瀏覽器要求的資產時,即時壓縮資產。
優點
- 您不需要建立與更新已儲存的資產壓縮版本。
- 對於動態產生的網頁而言,即時壓縮效果尤佳。
缺點
- 壓縮在較高層級的檔案可以達到更好的壓縮比率,需要較長的時間。這可能會導致效能命中,因為使用者等待素材資源在伺服器送出之前先壓縮。
使用 Node/Express 動態壓縮
server.js
檔案負責設定託管應用程式的節點伺服器。
const express = require('express');
const app = express();
app.use(express.static('public'));
const listener = app.listen(process.env.PORT, function() {
console.log('Your app is listening on port ' + listener.address().port);
});
目前只會匯入 express
,並使用 express.static
中介軟體在 public/
目錄中載入所有靜態 HTML、JS 和 CSS 檔案 (而且這些檔案是由 webpack 與每個版本建立)。
為了確保所有資產在每次發出請求時都會經過壓縮,可以使用壓縮中介軟體程式庫。第一步,是將其新增為 package.json
中的 devDependency
:
"devDependencies": {
//...
"compression": "^1.7.3"
},
並匯入伺服器檔案 server.js
:
const express = require('express');
const compression = require('compression');
並在掛接 express.static
「之前」將其新增為中介軟體:
//...
const app = express();
app.use(compression());
app.use(express.static('public'));
//...
現在,請重新載入應用程式,然後查看「Network」面板中的套件大小。
從 225 KB 到 61.6 KB!現在 Response Headers
中的 content-encoding
標頭會顯示伺服器傳送此檔案編碼為 gzip
的檔案。
靜態壓縮
「static」壓縮的概念是預先壓縮並儲存資產。
優點
- 再也不必擔心因為壓縮等級造成延遲問題。現在可以直接擷取檔案,不需要採取任何行動。
缺點
- 每個版本都需要壓縮資產。如果使用高壓縮率,建構時間可能會大幅增加。
使用 Node/Express 和 webpack 進行靜態壓縮
由於靜態壓縮需要預先壓縮檔案,因此您可以在建構步驟中修改 webpack 設定來壓縮資產。CompressionPlugin
可用於此操作。
第一步,是將其新增為 package.json
中的 devDependency
:
"devDependencies": {
//...
"compression-webpack-plugin": "^1.1.11"
},
如同任何其他 webpack 外掛程式,請將其匯入設定檔 webpack.config.js:
const path = require("path");
//...
const CompressionPlugin = require("compression-webpack-plugin");
並在 plugins
陣列中加入這個字串:
module.exports = {
//...
plugins: [
//...
new CompressionPlugin()
]
}
根據預設,外掛程式會使用 gzip
壓縮建構檔案。請參閱說明文件,瞭解如何新增使用其他演算法的選項,或加入/排除特定檔案。
當應用程式重新載入並重新建構時,現在系統會建立主要套件的壓縮版本。開啟 Glitch 主控台,查看由節點伺服器提供的最終 public/
目錄內的內容。
- 按一下「工具」按鈕。
- 按一下「Console」按鈕。
- 在主控台中執行下列指令,變更為
public
目錄,以查看當中的所有檔案:
cd public
ls
經過 gzip 壓縮的套件 main.bundle.js.gz
現已儲存在這裡。根據預設,CompressionPlugin
也會壓縮 index.html
。
接下來,只要指示伺服器在收到原始 JS 版本時,就傳送這些 gzip 壓縮檔案。方法是在檔案透過 express.static
提供之前,在 server.js
中定義新路徑。
const express = require('express'); const app = express(); app.get('*.js', (req, res, next) => { req.url = req.url + '.gz'; res.set('Content-Encoding', 'gzip'); next(); }); app.use(express.static('public')); //...
app.get
用於指示伺服器如何回應特定端點的 GET 要求。接著,回呼函式會用於定義處理這項要求的方式。路線的運作方式如下:
- 將
'*.js'
指定為第一個引數,表示每個觸發端點都會執行此方法,以擷取 JS 檔案。 - 在回呼中,
.gz
會附加至要求的網址,Content-Encoding
回應標頭則設為gzip
。 - 最後,
next()
可確保該序列繼續進行任何可能的回呼。
應用程式重新載入後,請再次查看 Network
面板。
和先前一樣,套裝組合的套裝組合有大幅縮減!
結論
本程式碼研究室涵蓋了壓縮及壓縮原始碼的程序。目前許多工具都會採用這兩種技術,因此請務必確認您的工具鍊是否已支援這些工具,或是您是否應該自行套用這兩個程序。