天天看點

webpack打包優化_前端性能優化:webpack性能調優與Gzip原理webpack 的性能瓶頸不要讓 loader 做太多事情——以 babel-loader 為例不要放過第三方庫

連結:https://juejin.im/book/5b936540f265da0a9624b04b

從輸入 URL 到顯示頁面這個過程中,涉及到網絡層面的,有三個主要過程:

  1. DNS 解析
  2. TCP 連接配接
  3. HTTP 請求/響應

對于 DNS 解析和 TCP 連接配接兩個步驟,我們前端可以做的努力非常有限。相比之下,HTTP 連接配接這一層面的優化才是我們網絡優化的核心。是以抓主要沖突,直接從 HTTP 開始講起。

HTTP 優化有兩個大的方向:

  1. 減少請求次數
  2. 減少單次請求所花費的時間

這兩個優化點直直地指向了我們日常開發中非常常見的操作——資源的壓縮與合并。沒錯,這就是我們每天用建構工具在做的事情。而時下最主流的建構工具無疑是 webpack,是以我們這節的主要任務就是圍繞業界霸主 webpack 來做文章。

webpack 的性能瓶頸

相信每個用過 webpack 的同學都對“打包”和“壓縮”這樣的事情爛熟于心。這些老生常談的特性,更推薦大家去閱讀文檔。

webpack 的優化瓶頸,主要是兩個方面:

  • webpack 的建構過程太花時間
  • webpack 打包的結果體積太大

webpack 優化方案

建構過程提速政策

不要讓 loader 做太多事情——以 babel-loader 為例

babel-loader 無疑是強大的,但它也是慢的。

最常見的優化方式是,用 include 或 exclude 來幫我們避免不必要的轉譯,比如 webpack 官方在介紹 babel-loader 時給出的示例:

module: { rules: [ { test: /.js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } } ]}           
webpack打包優化_前端性能優化:webpack性能調優與Gzip原理webpack 的性能瓶頸不要讓 loader 做太多事情——以 babel-loader 為例不要放過第三方庫

這段代碼幫我們規避了對龐大的 node_modules 檔案夾或者 bower_components 檔案夾的處理。但通過限定檔案範圍帶來的性能提升是有限的。除此之外,如果我們選擇開啟緩存将轉譯結果緩存至檔案系統,則至少可以将 babel-loader 的工作效率提升兩倍。要做到這點,我們隻需要為 loader 增加相應的參數設定:

loader: 'babel-loader?cacheDirectory=true'           

以上都是在讨論針對 loader 的配置,但我們的優化範圍不止是 loader 們。

舉個例子,盡管我們可以在 loader 配置時通過寫入 exclude 去避免 babel-loader 對不必要的檔案的處理,但是考慮到這個規則僅作用于這個 loader,像一些類似 UglifyJsPlugin 的 webpack 插件在工作時依然會被這些龐大的第三方庫拖累,webpack 建構速度依然會是以大打折扣。是以針對這些龐大的第三方庫,我們還需要做一些額外的努力。

不要放過第三方庫

第三方庫以 node_modules 為代表,它們龐大得可怕,卻又不可或缺。

處理第三方庫的姿勢有很多,其中,Externals 不夠聰明,一些情況下會引發重複打包的問題;而 CommonsChunkPlugin 每次建構時都會重新建構一次 vendor;出于對效率的考慮,這裡為大家推薦 DllPlugin。

DllPlugin 是基于 Windows 動态連結庫(dll)的思想被創作出來的。這個插件會把第三方庫單獨打包到一個檔案中,這個檔案就是一個單純的依賴庫。這個依賴庫不會跟着你的業務代碼一起被重新打包,隻有當依賴自身發生版本變化時才會重新打包。

用 DllPlugin 處理檔案,要分兩步走:

  • 基于 dll 專屬的配置檔案,打包 dll 庫
  • 基于 webpack.config.js 檔案,打包業務代碼

以一個基于 React 的簡單項目為例,我們的 dll 的配置檔案可以編寫如下:

const path = require('path')const webpack = require('webpack')module.exports = { entry: { // 依賴的庫數組 vendor: [ 'prop-types', 'babel-polyfill', 'react', 'react-dom', 'react-router-dom', ] }, output: { path: path.join(__dirname, 'dist'), filename: '[name].js', library: '[name]_[hash]', }, plugins: [ new webpack.DllPlugin({ // DllPlugin的name屬性需要和libary保持一緻 name: '[name]_[hash]', path: path.join(__dirname, 'dist', '[name]-manifest.json'), // context需要和webpack.config.js保持一緻 context: __dirname, }), ],}           
webpack打包優化_前端性能優化:webpack性能調優與Gzip原理webpack 的性能瓶頸不要讓 loader 做太多事情——以 babel-loader 為例不要放過第三方庫

編寫完成之後,運作這個配置檔案,我們的 dist 檔案夾裡會出現這樣兩個檔案:

vendor-manifest.jsonvendor.js           

vendor.js 不必解釋,是我們第三方庫打包的結果。這個多出來的 vendor-manifest.json,則用于描述每個第三方庫對應的具體路徑,我這裡截取一部分給大家看下:

{ "name": "vendor_397f9e25e49947b8675d