使用 brotli 壓縮網路酬載

Michael DiBlasio
Michael DiBlasio

本程式碼研究室是「縮減及壓縮網路酬載」程式碼研究室的延伸課程,假設您熟悉壓縮的基本概念。與 gzip 等其他壓縮演算法相比,這個程式碼研究室會探討 Brotli 壓縮 (br) 如何進一步降低壓縮比率和應用程式的整體大小。

應用程式螢幕截圖

測量

在著手新增最佳化功能前,建議您先分析應用程式的目前狀態。

  1. 按一下「Remix to Edit」,即可編輯專案。
  2. 如要預覽網站,請按下「View App」,然後按下「Fullscreen」全螢幕

在先前的壓縮網路酬載程式碼研究室中,我們將 main.js 的大小從 225 KB 縮減為 61.6 KB。在本程式碼研究室中,您將瞭解 Brotli 壓縮功能如何進一步縮減這個套件大小。

Brotli 壓縮

Brotli 是一種較新的壓縮演算法,可提供比 gzip 更優異的文字壓縮結果。根據 CertSimple 的說法,Brotli 的效能如下:

  • 比 JavaScript 的 gzip 小 14%
  • 比 HTML 的 gzip 小 21%
  • 比 CSS 的 gzip 小 17%

如要使用 Brotli,您的伺服器必須支援 HTTPS。所有新型瀏覽器都支援 Brotli。支援 Brotli 的瀏覽器會在 Accept-Encoding 標頭中加入 br

Accept-Encoding: gzip, deflate, br

您可以使用 Chrome 開發人員工具的「網路」分頁 (Command+Option+ICtrl+Alt+I) 中的 Content-Encoding 欄位,判斷要使用哪種壓縮演算法:

網路面板。「Content-encoding」欄會顯示各種資產使用的編碼,包括 gzip 和 brotli (br)。

如何啟用 Brotli

設定網頁伺服器以傳送 Brotli 編碼的資源,取決於您如何編碼。您可以選擇在要求時使用 Brotli 動態壓縮資源 (動態),或是預先編碼,讓資源在使用者要求時已完成壓縮 (靜態)。

動態壓縮

動態壓縮牽涉到即時壓縮瀏覽器要求的資產。

優點

  • 您不需要建立與更新已儲存的資產壓縮版本。
  • 對於動態產生的網頁,即時壓縮功能特別實用。

缺點

  • 在較高層級壓縮檔案可獲得較佳的壓縮率,但所需時間也較長。這可能會導致效能受損,因為使用者必須等待資產壓縮完成,伺服器才能傳送。

使用 Node 和 Express 進行動態壓縮

server.js 檔案負責設定託管應用程式的 Node 伺服器。

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/directory 中的所有靜態 HTML、JS 和 CSS 檔案 (這些檔案會在每次建構時由 webpack 建立)。

為確保每次要求時,所有資產都會使用 Brotli 進行壓縮,您可以使用 shrink-ray 模組。首先,請在 package.json 中將其新增為 devDependency

"devDependencies": {
  // ...
  "shrink-ray": "^0.1.3"
},

並匯入伺服器檔案 server.js

const express = require('express');
const shrinkRay = require('shrink-ray');

並在掛接 express.static 前將其新增為中介軟體:

// ...
const app = express();

// Compress all requests
app.use(shrinkRay());
app.use(express.static('public'));

接著重新載入應用程式,並查看「Network」面板中的套件大小:

使用動態 Brotli 壓縮功能的套件大小。

您現在可以看到 brotli 是從 bz 套用至 Content-Encoding 標頭。main.bundle.js 從 225 KB 縮減至 53.1 KB!與 gzip (61.6 KB) 相比,這個檔案小了約 14%。

靜態壓縮

靜態壓縮的概念是預先壓縮並儲存資產。

優點

  • 您不必再擔心因高壓縮率而造成的延遲問題。由於檔案現在可以直接擷取,因此不需要即時執行任何動作來壓縮檔案。

缺點

  • 每個版本都需要壓縮資產。如果使用較高的壓縮等級,建構時間可能會大幅增加。

使用 webpack 搭配 Node 及 Express 的靜態壓縮

由於靜態壓縮涉及提前壓縮檔案,因此您可以修改 webpack 設定,在建構步驟中壓縮資產。brotli-webpack-plugin 可用於此用途。

首先,請在 package.json 中將其新增為 devDependency

"devDependencies": {
  // ...
 "brotli-webpack-plugin": "^1.1.0"
},

如同其他 webpack 外掛程式,請在設定檔 webpack.config.js 中匯入:

var path = require("path");

//...
var BrotliPlugin = require('brotli-webpack-plugin');

並將其加入 plugins 陣列中:

module.exports = {
  // ...
  plugins: [
    // ...
    new BrotliPlugin({
      asset: '[file].br',
      test: /\.(js)$/
    })
  ]
},

外掛程式陣列會使用下列引數:

  • asset:目標資產名稱。
  • [file] 會替換成原始素材資源檔案名稱。
  • test:系統會處理所有符合此規則運算式的資產 (也就是結尾為 .js 的 JavaScript 資產)。

舉例來說,main.js 可能會重新命名為 main.js.br

當應用程式重新載入及重新建構時,系統會建立主要套件的壓縮版本。開啟 Glitch 控制台,查看 Node 伺服器提供的最終 public/ 目錄內的內容。

  1. 按一下「工具」按鈕。
  2. 按一下「Console」按鈕。
  3. 在主控台中執行下列指令,切換至 public 目錄並查看所有檔案:
cd public
ls -lh
使用靜態 Brotli 壓縮的 Bundle 大小

套件的 brotli 壓縮版本 main.bundle.js.br 現在也已儲存在此處,其大小比 main.bundle.js 小約 76% (225 KB 與 53 KB)。

接下來,請告訴伺服器,在使用者要求原始 JS 版本時傳送這些經過 Brotli 壓縮的檔案。方法是在檔案透過 express.static 提供服務之前,在 server.js 中定義新的路徑。

const express = require('express');
const app = express();

app.get('*.js', (req, res, next) => {
  req.url = req.url + '.br';
  res.set('Content-Encoding', 'br');
  res.set('Content-Type', 'application/javascript; charset=UTF-8');
  next();
});

app.use(express.static('public'));

app.get 可用於告知伺服器如何回應特定端點的 GET 要求。接著,回呼函式會用於定義處理這項要求的方式。路線的運作方式如下:

  • '*.js' 指定為第一個引數,表示這可用於擷取 JS 檔案的每個端點。
  • 在回呼中,.br 會附加至要求的網址,Content-Encoding 回應標頭則會設為 br
  • Content-Type 標頭設為 application/javascript; charset=UTF-8,以便指定 MIME 類型。
  • 最後,next() 會確保序列會繼續傳送至下一個可能的回呼。

由於部分瀏覽器可能不支援 Brotli 壓縮,因此請先確認瀏覽器支援 Brotli,再傳回 Brotli 壓縮檔案,方法是檢查 Accept-Encoding 要求標頭是否包含 br

const express = require('express');
const app = express();

app.get('*.js', (req, res, next) => {
  if (req.header('Accept-Encoding').includes('br')) {
    req.url = req.url + '.br';
    console.log(req.header('Accept-Encoding'));
    res.set('Content-Encoding', 'br');
    res.set('Content-Type', 'application/javascript; charset=UTF-8');
  }

  next();
});

app.use(express.static('public'));

應用程式重新載入後,請再次查看「Network」面板。

組合大小為 53.1 KB (從 225 KB 開始)

大功告成!您已使用 Brotli 壓縮功能進一步壓縮素材資源!

結論

本程式碼研究室說明 brotli 如何進一步縮減應用程式的整體大小。如果支援,brotli 是比 gzip 更強大的壓縮演算法。