webpack 構建優化


初級分析:使用 webpack 內置的 stats

stats: 構建的統計信息

package.json 中使用 stats

"script": {
  "build:stats": "webpack --env production --json > stats.json"
},

Node.js 中使用

const webpack = require("webpack");
const config = require("./webpack.config.js")("production")

webpack(config, (err, stats) => {
  if(err) {
    return console.error(err);
  }
  if(stats.hasErrors()) {
    return console.error(stats.toString("error-only"));
  }
  console.log(stats);
}) 

速度分析:使用 speed-measure-webpack-plugin

代碼示例

const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();

const webpackConfig = smp.wrap({
  plugins: [
    new MyPlugin(),
    new MyOtherPlugin()
  ]
})''

可以看到每個 loader 和插件執行耗時

速度分析插件作用

分析整個打包總耗時

每個插件和loader的耗時情況

webpack-bundle-analyzer 分析體積

代碼示例

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
}

構建完成后會在 8888 端口展示大小。

可以分析哪些問題?

依賴的第三方模塊文件大小

業務里面的組件代碼大小

使用高版本的 webpack 和 Node.js

使用 webpack4:優化原因

  • V8 帶來的優化(for of 替代 forEach、Map 和 Set 替代 Object、includes 替代 indexOf)
  • 默認使用更快的 md4 hash 算法
  • webpacks AST 可以直接從 loader 傳遞給 AST,減少解析時間
  • 使用字符串方法替代正則表達式

多進程/多實例構建:資源並行解析可選方案

多進程/多實例:使用 HappyPack 解析資源

原理:每次 webapck 解析一個模塊,HappyPack 會將它及它的依賴分配給 worker 線程中

代碼示例

多進程/多實例:使用 thread-loader 解析資源

原理:每次 webpack 解析一個模塊,thread- loader 會將它及它的依賴分配給 worker 線程中

多進程/多實例:並行壓縮

方法一:使用 parallel-uglify-plugin 插件

方法二:uglifyjs-webpack-plugin 開啟 parallel 參數

方法三:terser-webpack-plugin 開啟 parallel 參數

分包:設置 Externals

思路:將 react、react-dom 基礎包通過 cdn 引入,不打入 bundle 中

方法:使用 html-webpack-externals- plugin

進一步分包:預編譯資源模塊

思路:將 react、react-dom、redux、react-redux 基礎包和業務基礎包打包成一個文件

方法:使用 DLLPlugin 進行分包,DllReferencePlugin 對 manifest.json 引用

使用 DLLPlugin 進行分包

使用 DllReferencePlugin 引用 manifest.json

在 webpack.config.js 引入

緩存

目的:提升二次構建速度

緩存思路:

  • babel-loader 開啟緩存
  • terser-webpack-plugin 開啟緩存
  • 使用 cache-loader 或者 hard-source-webpack-plugin

縮小構建目標

目的:盡可能的少構建模塊

比如 babel-loader 不解析 node_modules

減少文件搜索范圍

優化 resolve.modules 配置(減少模塊搜索層級)

優化 resolve.mainFields 配置

優化 resolve.extensions 配置

合理使用 alias

圖片壓縮

要求:基於 Node 庫的 imagemin 或者 tinypng API

使用:配置 image-webpack-loader

Imagemin的優點分析

  • 有很多定制選項

  • 可以引入更多第三方優化插件,例如pngquant

  • 可以處理多種圖片格式

Imagemin的壓縮原理

pngquant: 是一款PNG壓縮器,通過將圖像轉換為具有alpha通道(通常比24/32位PNG 文件小60-80%)的更高效的8位PNG格式,可顯著減小文件大小。

pngcrush:其主要目的是通過嘗試不同的壓縮級別和PNG過濾方法來降低PNG IDAT數據 流的大小。

optipng:其設計靈感來自於pngcrush。optipng可將圖像文件重新壓縮為更小尺寸,而不 會丟失任何信息。

tinypng:也是將24位png文件轉化為更小有索引的8位圖片,同時所有非必要的metadata 也會被剝離掉

tree shaking(搖樹優化)復習

概念:1 個模塊可能有多個方法,只要其中的某個方法使用到了,則整個文件都會被打到 bundle 里面去,tree shaking 就是只把用到的方法打入 bundle ,沒用到的方法會在 uglify 階段被擦除掉。

使用:webpack 默認支持,在 .babelrc 里設置 modules: false 即可 · production mode的情況下默認開啟

要求:必須是 ES6 的語法,CJS 的方式不支持

無用的 CSS 如何刪除掉?

PurifyCSS: 遍歷代碼,識別已經用到的 CSS class

uncss: HTML 需要通過 jsdom 加載,所有的樣式通過PostCSS解析,通過 document.querySelector 來識別在 html 文件里面不存在的選擇器

在 webpack 中如何使用 PurifyCSS?

構建體積優化:動態 Polyfill

babel-polyfill

打包后體積:88.49k,占比 29.6%

Promise 的瀏覽器支持情況

​ Can I user ____?

構建體積優化 :動態 Polyfill

方案 優點 缺點 是否采用
babel-polyfill react官方推薦 1. 包體積200K+,難以單獨抽離Map、Set
2. 項目里如果 react 單獨引用的 cdn,如果需要用它需要單獨構建一份放在 react 前面加載
babel-plugin-transform-runtime 體積小 不能在 polyfill 原型上方法。不適用於業務復雜的項目開發環境
自己的 Map、Set 的 polyfill 定制化高、體積小 1.重復造輪子
2.自己填坑
3.體積小,但是所有都要加載
polyfill-service 只給用戶需要的 polyfill,社區維護 部分國內奇葩瀏覽器可能無法識別(但是可以降級返回所需的全部 polyfill)

Polyfill Service原理

識別 User Agent,下發不同的 Polyfill

構建體積優化:如何使用動態 Polyfill service

polyfill.io 官方提供的服務

<script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script>

基於官方自建的 polyfill 服務

自己去找了

體積優化策略總結

  • Scope Hoisting

  • Tree-shaking

  • 公共資源分離

  • 圖片壓縮

  • 動態 Polyfill


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM