Blazor 釋出WebAssembly使用Brotli 壓縮提升初次載入速度

AlexChow發表於2022-04-09

使用Brotli提高網站訪問速度

在優化網站開啟速度上,我們有很多的方法,而其中一個就是減少諸如Javascript和CSS等資原始檔的大小,而減少檔案大小的方法除了在程式碼上下功夫外,最常用的方法就是使用壓縮演算法對檔案進行壓縮。

目前,網站普遍使用的是gzip壓縮演算法,但是最近兩年新興了一個新的壓縮演算法:Brotli,下面我將會對這個演算法進行簡單的介紹。

什麼是Brotli

Brotli是一個Jyrki Alakuijala和Zoltán Szabadka開發的開源資料壓縮程式庫, Brotli基於LZ77演算法的一個現代變體、霍夫曼編碼和二階上下文建模。最初釋出於2015年,用於網路字型的離線壓縮。Google軟體工程師在2015年9月釋出了包含通用無損資料壓縮的Brotli增強版本,特別側重於HTTP壓縮。其中的編碼器被部分改寫以提高壓縮比,編碼器和解碼器都提高了速度,流式API已被改進,增加更多壓縮質量級別。新版本還展現了跨平臺的效能改進,以及減少解碼所需的記憶體。

與常見的通用壓縮演算法不同,Brotli使用一個預定義的120千位元組字典。該字典包含超過13000個常用單詞、短語和其他子字串,這些來自一個文字和HTML文件的大型語料庫。預定義的演算法可以提升較小檔案的壓縮密度。

使用brotli取代deflate來對文字檔案壓縮通常可以增加20%的壓縮密度,而壓縮與解壓縮速度則大致不變。

WASM壓縮

釋出 Blazor WebAssembly 應用時,將在釋出過程中對輸出內容進行靜態壓縮,從而減小應用的大小,並免去執行時壓縮的開銷。 使用以下壓縮演算法:

  • Brotli(級別最高)
  • Gzip
    Blazor 依賴於主機提供適當的壓縮檔案。 使用 ASP.NET Core 託管專案時,主機專案能夠執行內容協商並提供靜態壓縮檔案。 託管 Blazor WebAssembly 獨立應用時,可能需要額外的工作來確保提供靜態壓縮檔案:

有關 IIS web.config 壓縮配置,請參閱 IIS:Brotli 和 Gzip 壓縮 部分。

如果在不支援靜態壓縮檔案內容協商的靜態託管解決方案(例如 GitHub 頁面)上進行託管,請考慮配置應用以提取和解碼 Brotli 壓縮檔案:

google/brotli GitHub repository 中獲取 JavaScript Brotli 解碼器。 縮小的解碼器檔案被命名為 decode.min.js,並且位於儲存庫的 js 資料夾中。

更新應用以使用解碼器。

在 wwwroot/index.html 檔案中,在 Blazor 的 script 標記上將 autostart 設定為 false:

<script src="_framework/blazor.webassembly.js" autostart="false"></script>

在下面已經新增:

<script type="module">
  import { BrotliDecode } from './decode.min.js';
  Blazor.start({
    loadBootResource: function (type, name, defaultUri, integrity) {
      if (type !== 'dotnetjs' && location.hostname !== 'localhost') {
        return (async function () {
          const response = await fetch(defaultUri + '.br', { cache: 'no-cache' });
          if (!response.ok) {
            throw new Error(response.statusText);
          }
          const originalResponseBuffer = await response.arrayBuffer();
          const originalResponseArray = new Int8Array(originalResponseBuffer);
          const decompressedResponseArray = BrotliDecode(originalResponseArray);
          const contentType = type === 
            'dotnetwasm' ? 'application/wasm' : 'application/octet-stream';
          return new Response(decompressedResponseArray, 
            { headers: { 'content-type': contentType } });
        })();
      }
    }
  });
</script>

有關載入啟動資源的詳細資訊,請參閱 ASP.NET Core Blazor 啟動

伺服器Nginx配置

執行nginx -V檢查是否帶br, 檢查 module= ngx_brotli 關鍵字. 如果不帶,自行編譯安裝.

nginx -V
nginx version: nginx/1.20.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) 
built with OpenSSL 1.1.1k  25 Mar 2021
TLS SNI support enabled
configure arguments: --user=www --group=www --prefix=/www/server/nginx --add-module=/www/server/nginx/src/ngx_devel_kit --add-module=/www/server/nginx/src/lua_nginx_module --add-module=/usr/src/ngx_brotli --add-module=/www/server/nginx/src/ngx_cache_purge --add-module=/www/server/nginx/src/nginx-sticky-module --with-openssl=/www/server/nginx/src/openssl --with-pcre=pcre-8.43 --with-http_v2_module --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-http_stub_status_module --with-http_ssl_module --with-http_image_filter_module --with-http_gzip_static_module --with-http_gunzip_module --with-ipv6 --with-http_sub_module --with-http_flv_module --with-http_addition_module --with-http_realip_module --with-http_mp4_module --with-ld-opt=-Wl,-E --with-cc-opt=-Wno-error --with-ld-opt=-ljemalloc --with-http_dav_module --add-module=/www/server/nginx/src/nginx-dav-ext-module

brotli 配置

# brotli 配置開始
brotli on;
brotli_comp_level 6;  #壓縮等級,預設6,最高11,太高的壓縮水平可能需要更多的CPU
brotli_buffers 16 8k;  #請求緩衝區的數量和大小
brotli_min_length 100; #指定壓縮資料的最小長度,只有大於或等於最小長度才會對其壓縮。這裡指定100位元組
brotli_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/json image/svg application/font-woff application/vnd.ms-fontobject application/vnd.apple.mpegurl image/x-icon image/jpeg image/gif image/png image/bmp;  #指定允許進行壓縮型別
brotli_static always;   #是否允許查詢預處理好的、以.br結尾的壓縮檔案,可選值為on、off、always
brotli_window 512k;  #視窗值,預設值為512k
proxy_set_header Accept-Encoding "";
# brotli 配置結束

測試結果

新建預設wasm工程,非pwa

方式 釋出後 rar壓縮包 chrome 隱私模式 edge隱私模式 備註
WASM+BR 15.5 m 8.76 m 1.87s 2.09s
WASM AOT 32.5 m 16.2 m 3.75s 2.8s
WASM+BR (net7pre2) 16.2 m 9.05 m 1.91s 2.68s net6工程升級
WASM AOT (net7pre2) 27.7 m 14.6 m 2.54s 2.69s net6工程升級
WASM+BR (net7pre2) 16.2 m 9.23 m 1.89s 1.99s 新建工程
WASM AOT (net7pre2) 36.3 m 17.3 m 2.52s 2.75s 新建工程

結論

  1. 在不支援靜態壓縮檔案內容協商的靜態託管解決方案使用decode.min.js的確可以呼叫br解壓縮,在啟用br的nginx上就無需這個操作了,因為使用和不使用decode.min.js實際請求發傳送都是完全一致的.br檔案.

  2. PWA方式是不能用decode.min.js的, 會直接會導致pwa離線功能失效. 在啟用br的nginx上就走nginx自己的br就夠了.會自動命中釋出的br資源.

技巧

提示hash校驗失敗, 可以強制關掉或者自己再算一遍

map(asset => new Request(asset.url, {  cache: 'no-cache' }));

配圖

測試一: WASM + BR

測試一 WASM

2 (480)
3 (480)
1 (608)
4 (854)
5 (750)

測試二: WASM + AOT + BR

測試二 WASM AOT

2 (480)
3 (480)
1 (608)
4 (854)
5 (839)

知識共享許可協議

本作品採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名AlexChow(包含連結: https://github.com/densen2014 ),不得用於商業目的,基於本文修改後的作品務必以相同的許可釋出。如有任何疑問,請與我聯絡

AlexChow

今日頭條 | 部落格園 | 知乎 | Gitee | GitHub

相關文章