說到優化,首先肯定要通過一些分析工具找出項目存在的問題,然後針對問題來做對應的優化。
webpack優化分為兩個方向:
1.建構速度層面優化
安裝打包耗時分析插件:
npm install --save-dev speed-measure-webpack-plugin
使用方法:
// 導入速度分析插件
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
// 執行個體化插件
const smp = new SpeedMeasurePlugin();
//調用wrap方法,傳入webpack配置對象
smp.wrap({
plugins: []
})
2.代碼輸出品質優化
安裝打包體積分析插件:
npm install --save-dev webpack-bundle-analyzer
// 導入體積分析插件
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
plugins: [
// 執行個體化體積分析插件
new BundleAnalyzerPlugin()
]
//執行打包指令之後,本地http://127.0.0.1:8888/頁面可檢視打包後體積分布
建構速度層面優化:
1.縮小打包作用域
1.1 test/exclude/include 确定loader規則範圍
1.2 resolve.modules 預設值為['node_modules'],含義是先去目前目錄的node_modules下去找子產品,沒有找到就去上一級../node_modules中找,當第三方子產品的路徑确定時,可以指定其絕對路徑,以減少尋找。
module.exports={
resolve:{
modules:[path.resolve(__dirname,'node_modules')]
}
}
1.3 resolve.mainFields
當webpack的target屬性設定為 webworker, web 或者沒有指定,預設值為:
mainFields: ["browser", "module", "main"]
對于其他任意的 target(包括 node),預設值為:
mainFields: ["module", "main"]
為了減少搜尋步驟,如果你使用到的第三方子產品的入口檔案描述字段都是main時,可以把mainFields設為['main']
1.4 alias 配置别名
通過配置别名來将原導入路徑映射成一個新的導入路徑,例如一些龐大的第三方子產品,可以用别名指定其公共檔案,進而跳過耗時的遞歸解析操作。
1.5 resolve.extensions 盡可能減少字尾嘗試的可能性
在源碼的導入時,也盡可能帶上字尾,避免尋找過程
1.6 noParse 對完全不需要解析的庫進行忽略
防止 webpack 解析那些任何與給定正規表達式相比對的檔案。忽略的檔案中不應該含有 import, require, define 的調用,或任何其他導入機制。忽略大型的 library 可以提高建構性能
1.7 預編譯資源子產品
DllPlugin結合DllReferencePlugin
或者:
hard-source-webpack-plugin ,配置簡單,推薦使用
把複用性較高的第三方子產品打包到動态連結庫中,在不更新這些庫的情況下,動态庫不需要重新打包,每次建構隻重新打包業務代碼
2.多程序建構
2.1 thread-loader插件
webpack 是單線程模型的,是以webpack 需要一個一個地處理任務,不能同時處理多個任務。
thread-loader會将你的 loader 放置在一個 worker 池裡面運作,以達到多線程建構。
2.2 多程序并行壓縮代碼
webpack預設提供了UglifyJS插件來壓縮JS代碼,但是它使用的是單線程壓縮代碼,也就是說多個js檔案需要被壓縮,它需要一個個檔案進行壓縮
目前有三種主流的多程序壓縮方案:
parallel-uglify-plugin
uglifyjs-webpack-plugin
terser-webpack-plugin
這些插件能開啟多個子程序,把對多個檔案壓縮的工作分别給多個子程序去完成,但是每個子程序還是通過UglifyJS去壓縮代碼。無非就是變成了并行處理該壓縮了,并行處理多個子任務,效率會更加的提高
3.充分利用緩存
3.1 cache-loader
代碼輸出品質優化
1. 用 webpack 實作 CDN 的接入
靜态資源的導入 URL 需要變成指向 CDN 服務的絕對路徑的 URL 而不是相對于 HTML 檔案的 URL。
靜态資源的檔案名稱需要帶上有檔案内容算出來的 Hash 值,以防止被緩存。
不同類型的資源放到不同域名的 CDN 服務上去,以防止資源的并行加載被阻塞。
web-webpack-plugin 單頁面應用生成 HTML 檔案
extract-text-webpack-plugin
2. 多入口項目提取公共代碼
SplitChunksPlugin 進行(公共腳本、基礎包、頁面公共檔案)分離(Webpack4内置)
3. 按需加載
webpack支援兩種動态代碼拆分技術:
- import()文法,用import引入的子產品以及其子子產品會被分割打包成一個獨立的chunk
- 傳統的require.ensure
4. 使用tree shaking
tree shaking是一個術語,通常用于描述移除 JavaScript 上下文中的未引用代碼(dead-code)。它依賴于 ES2015 子產品系統中的靜态結構特性,例如 import和 export
使用:
- 使用 ES2015 子產品文法(即 import 和 export)。
- 導入子產品副作用的設定,在項目 package.json 檔案中,添加一個 sideEffects入口,或者在module.rules配置選項中設定 sideEffects。
- 引入一個能夠删除未引用代碼(dead code)的壓縮工具(minifier)(例如 UglifyJSPlugin)。
5. 動态 Polyfill 服務
babel-polyfill由于是一次性全部導入整個polyfill,是以用起來很友善,但與此同時也帶來了一個大問題:檔案很大
動态 polyfill 指的是根據不同的浏覽器,動态載入需要的 polyfill。 http://Polyfill.io 通過嘗試使用 polyfill 重新建立缺少的功能,可以更輕松地支援不同的浏覽器,并且可以大幅度的減少建構體積。
使用方法:在 index.html 中引入如下 script 标簽
<script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js"></script>
6. 啟用Scope Hoisting
Scope hoisting(作用域提升),即讓webpack 會把引入的 js 檔案“提升到”它的引入者頂部。
Scope Hoisting 可以讓 Webpack 打包出來的代碼檔案更小、運作的更快。
Webpack 内置的功能,隻需要配置一個插件
plugins: [new webpack.optimize.ModuleConcatenationPlugin()]