webpack & HTTP/2

薛定諤的貓發表於2017-10-19

webpack & HTTP/2

讓我們從 HTTP/2 的一個傳言開始:

有了 HTTP/2,你就不再需要打包模組了。

HTTP/2 可以多路複用,所有模組都可以並行使用同一個連線,因此多個請求不再需要多餘的往返開銷。每個模組都可以獨立快取。

很遺憾,現實並不如意。

以前的文章

下面的文章詳細解釋了相關資訊,並且做了一些實驗來驗證。你可以閱讀它們(或者跳過它們,只看總結)。

Forgo JS packaging? Not so fast The traditional advice for web developers is to bundle the JavaScript files used by their webpages into one or (at most…engineering.khanacademy.org

The Right Way to Bundle Your Assets for Faster Sites over HTTP/2 Speed is always a priority in web development. With the introduction of HTTP/2, we can have increased performance for a…medium.com

文章主旨:

  • 相比拼接為一個檔案,多個檔案傳輸仍然有 協議開銷(protocol overhead)
  • 相比多個小檔案,單檔案方式對壓縮更友好。
  • 相比處理單個大檔案,伺服器處理多個小檔案較慢。

因此我們需要在兩者中間取得一個折中。我們將模組分為 n 個包,n 大於 1,小於模組數。改變其中一個模組使其快取失效,因為相應的包只是整個應用的一部分,其它的包的快取仍然有效。

更多的包意味著快取命中率更高,但不利於壓縮。

AggressiveSplittingPlugin

webpack 2 為你提供了這樣的工具。webpack 內部大多都是這樣,將一組模組組裝成塊(chunk)輸出一個檔案。我們還有一個優化階段可以改變這些塊(chunk),只是需要一個外掛來做這個優化。

外掛 AggressiveSplittingPlugin 將原始的塊分的更小。你可以指定你想要的塊大小。它提高了快取,但不利於壓縮(對 HTTP/1 來說也影響傳輸時間)。

為了結合相似的模組,它們在分離之前會按照路徑的字母順序排序。通常在同一目錄下的檔案往往是相關的,從壓縮來看也是一樣。通過這種排序,它們也就能分離到相同的塊中了。

對於 HTTP/2 我們現在有高效的分塊方式了。

修改應用

但這還沒結束。當應用更新時我們要儘量複用之前建立的塊。因此每次 AggressiveSplittingPlugin 都能夠找到一個合適的塊大小(在限制內),並將塊的模組(modules)和雜湊(hash)儲存到 records 中。

Records 是 webpack 編譯過程中編譯狀態的概念,可以通過 JSON 檔案存取。

當再次呼叫 AggressiveSplittingPlugin,在嘗試分離剩餘模組之前,它會先嚐試從 records恢復塊。這就確保已快取的塊能夠被複用。

啟動和服務(Bootstrapping and Server)

使用這項技術的應用不再輸出包含在 HTML 檔案中的單獨檔案,相反,它輸出多個需要被載入的塊(chunk),應用就能使用多個 script 標籤(並行)載入每個塊。就像這樣:

<script src="1ea296932eacbe248905.js"></script>
<script src="0b3a074667143853404c.js"></script>
<script src="0dd8c061aff2a2791815.js"></script>
<script src="191b812fa5f7504151f7.js"></script>
<script src="08702f45497539ef6ea6.js"></script>
<script src="195c9326275620b0e9c2.js"></script>
<script src="19817b3a0378aedb2143.js"></script>
<script src="0e7a65e649387d773247.js"></script>
<script src="13167c9702de79d2f4fd.js"></script>
<script src="1154be40ff0e8dd16e9f.js"></script>
<script src="129ce3c198a25d9ace74.js"></script>
<script src="032d1fc9a213dfaf2c79.js"></script>
<script src="07df084bbafc95c1df47.js"></script>
<script src="15c45a570bb174ae448e.js"></script>
<script src="02099ada43bbf02a9f73.js"></script>
<script src="17bc99aaed6b9a23da78.js"></script>
<script src="02d127598b1c99dcd2d0.js"></script>複製程式碼

webpack按時間先後順序輸出這些塊。最舊的檔案先執行,最新的在最後。瀏覽器可以先執行已被快取的塊,同時載入最新的檔案 -- 舊檔案更可能已經被快取。

當 HTML 檔案被請求時,HTTP/2 服務端推送可以將這些塊推送給客戶端。也是因為舊檔案更可能已經被快取,最好能先推送最新的檔案。如果已經有快取,客戶端可以取消服務端的推送,但這需要一次往返。

webpack 將程式碼分離用於 按需載入,可以處理並行請求。

結論

webpack 2 為你提供了用於 HTTP/2 的,能改善快取和傳輸的工具。不用擔心你的技術棧不面向未來了。

注意 AggressiveSplittingPlugin 仍然是實驗特性

我對你的使用體驗很感興趣哦~


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOSReact前端後端產品設計 等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章