當前位置:
首頁 > 科技 > JS/CSS體積減少了67%,我們是如何做到的?

JS/CSS體積減少了67%,我們是如何做到的?

作者 | Guilherme Oenning

譯者 | 邱仁博

Fider(Fider 是一款開源的產品反饋搜集平台)團隊一直致力於優化應用程序的體驗。作為一個使用 React 構建的 web 應用程序,他們主要關注如何減少 JS 和 CSS 代碼的體積。在這篇文章中,Fider 團隊分享了他們的學習體會。通過掌握這些概念和建議,你也可以針對自己的 Web 應用做出類似的優化。

Fider 的前端由 React 和 Webpack 構建,所以下面的主題非常適用於使用相同技術棧的前端團隊,但是這些概念也可以應用於其他技術棧。Fider 本身是一個開源項目,所以你實際上可以在項目地址上提交 PR 或者查看源碼。

1

Bundle 可視化分析器

webpack-bundle-analyzer 是一個 Webpack 插件,它可以將你所使用的 Bundle 生成為一個可交互、可縮放 Treemap。通過這個插件,你可以看到 Bundle 中哪個 Module 佔用體積最大。

如果你不知道產生問題的根本原因,你怎麼能解決它呢?

下圖是 webpack-bundle-analyzer 生成結果的示例。

在考慮 Bundle 體積前,先用 webpack-bundle-analyzer 進行分析,是一個很好的習慣。

2

長期緩存

Long term caching 是指告知瀏覽器長時間緩存一個文件,比如 3 個月甚至 1 年。它之所以非常重要,是因為這項特性可以確保再次返回同一頁面瀏覽的用戶,不需要重複下載相同的 JS/CSS 文件。

瀏覽器是根據文件的完整路徑名來緩存文件的。因此,假如你需要強制用戶下載新版本的 Bundle,首先必須重命名這個 Bundle。幸運的是,Webpack 提供了一個功能,可以根據一定規則來更新 Bundle 的名稱,從而解決這個問題。

長久以來,Fider 團隊一直把 Chunkhash 作為 Webpack 編譯輸出的配置。但是在 99% 的需要 Long Term Caching 的場景中,最好的選擇 Contenthash。它將根據 JS/CSS 的內容生成散列,因此只有內容發生改變,Bundle 的命名才會變化,從而儘可能的利用 Long Term Caching 的優勢。

儘管這種技術不會減少 Bundle 的大小,但它確實有助於減少用戶下載 Bundle 的時間。如果某個 Bundle 沒有更改,用戶就無需再次下載它。

更多相關信息可以從 Webpack 官方文檔中獲取:

https://webpack.js.org/guides/caching/

3

公共 Bundle

長久以來,許多團隊在實踐中,都會將所有的 NPM Package 構建成一個單獨的 Bundle。這與 Long Term Caching 相結合時非常有用。

相比我們應用自身的代碼,NPM Package 的改動往往要小得多。因此我們可以把這些包單獨打包成一個 Bundle,從而避免用戶重複下載這些 NPM Package。這些由 Npm Package 構建成的 Bundle 通常稱為 Vendor Bundle。

但是我們可以做的更好。如果你自己也有一部分很少更改的代碼呢?也許你已經有了一些在一段時間之前創建,並且迄今為止很少修改的組件,如 Button,Grid,Toggle 等,那麼這些組件就可以作為 Common Bundle 的候選。

你可以看看 PR #636:

https://github.com/getfider/fider/pull/636

在這個 PR 中,我們就是把一些特定文件夾中的 Module 單獨構建成了一個 Common Bundle。這將確保,除非我們更改這些公共組件,否則用戶就不需要重新下載它們。

4

路由級別代碼分割

Code Splitting 是當前的熱門話題。代碼分割在過去不是一件簡單的事,但是隨著工具和框架的長足發展,現在進行 Code Splitting 相對而言簡單得多。

一種常見的情況是,即使用戶只是需要查看主頁,應用程序也會推送一個包含所有 JS/CSS 的 Bundle。這些 JS/CSS 可以用來渲染應用程序內的所有頁面。因為我們已經推送了所有的 JS/CSS 代碼,所以不用去關心用戶是否會去訪問站點內的其他頁面,比如設置頁面。Fider 這麼做已經很久了,但是現在我們已經做出了改變。

Code Splitting 的思想是生成一個 MainBundle 以及多個更小的 Bundle(通常一個路由對應一個)。我們唯一分發給所有用戶的是 Main Bundle,然後由 Main Bundle 非同步下載當前頁面渲染所需的 Bundle。

這看起來很複雜,但是多虧了 React 和 Webpack 這對組合,Code Splitting 已經不是什麼難事了。對於 React 5

按需載入外部依賴

通過使用 Webpack Bundle Analyzer,我們注意到,在 Vendor Bundle 中引入了 response-toastify。response-toastify 是我們用於彈出消息提示的 toaster 庫。在 Fider 中,我們很少彈出消息,那麼把 response-toastify 直接引入 Bundle 就不是非常合理。假如用戶並不需要顯示彈出消息,那為什麼要向他們推送這 30kB 的 JavaScript 代碼呢?

這個問題和第四節的問題很相似,但是這裡我們討論不再是路由,這是在多個路由中使用的某個特性。你能在 feature 級別上進行 Code Splitting 嗎?

是的,完全可以!

簡而言之,你需要做的就是從靜態導入切換到動態導入。

這樣,Webpack 會將 toastify 模塊及其 NPM 依賴項單獨打包。之後瀏覽器就會在需要 toast 的時候下載對應的 Bundle。如果您已經配置了 Long term caching,那麼在第二個 toaster 調用時就無需再次下載。下面這個動圖就顯示了這個過程。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 InfoQ 的精彩文章:

沒想到你是這樣的AWS
程序員的「年關」:這年終考核可咋整?

TAG:InfoQ |