banner
他山之石

他山之石

Webpack之打包體積優化

本文是我在使用 Webpack4 過程中的一些總結,介紹一些優化 Webpack 打包體積的方法。

image

Webpack 是當前大型專案的主流打包方案,自從將 react 的腳手架升級 Webpack4 以來,我也在不斷嘗試摸索 webpack 打包優化的一些方案。本文將從以下幾個方面,對於如何優化 Webpack 的打包體積,進行一些總結。

Bundle 分析#

webpack-bundle-analyzer 可以對打包輸出的 chunk 進行可視化分析,可以看到打包後每個模塊的大小,還能給出 gizp 壓縮後的大小,在生產環境中加載的模塊都是經過 gzip 壓縮過的,可以作為真實訪問的大小依據。

npm install --save-dev webpack-bundle-analyzer
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
}

Tree-Shaking#

Webpack4 在 mode 為 production 的情況下默認開啟了 Tree-Shaking,但在你的專案中可能會因為 babel 的原因導致它失效。

因為 Tree Shaking 這個功能是依賴於 ES2015 模塊系統中的靜態結構特性,例如 import 和 export。來找出未使用的代碼,所以如果你使用了 babel 插件的時候,如:babel-preset-env,它默認會將模塊打包成 commonjs,這樣就會讓 Tree Shaking 失效了。

所以需要配置 babel 不 transform modules。配置如下:

// .babelrc
{
  "presets": [
    ["env", {
      modules: false,
      ...
    }]
  ]
}

url-loader、file-loader 配置優化#

url-loader 和 file-loader 一般用來處理背景圖,默認會把 css 中的背景圖打包成 Base64,當 css 中的背景圖過大,會造成打包後的 css 變得龐大,在單頁應用中,css 阻塞 DOM 渲染,造成首頁白屏時間過長。曾遇到過某專案 build 後 css 多達 4M,嚴重影響用戶體驗,解決辦法是配置 url-loader 的 limit 字段,超過一定字節則不打包成 base64。配置後重新打包後的 css 約 300k。

{
    test: /\.(jpg|png|gif|svg)$/,
    loader: 'url-loader',
    include: path.join(__dirname, './src'),
    exclude: /node_modules/,
    options: {
        limit: 8192,
        name: 'images/[name].[hash:7].[ext]'
    }
}

按需加載#

當我們使用 React、Vue 開發 SPA 應用時,webpack 默認會輸出一個 js 文件,這意味這首屏渲染的時候,會加載完所有的頁面 js,js 體積過大極大影響首屏渲染速度,按需加載是一個不錯的選擇,對每一個路由對應的頁面打包成單獨的 chunk。目前最流行的辦法是使用動態 import 的方法。在 react 專案中,你可以使用 react-loadable 這個第三方庫。

import Loadable from 'react-loadable';
import Loading from './my-loading-component';

const LoadableComponent = Loadable({
  loader: () => import('./my-component'),
  loading: Loading,
});

<Route path="/user" component={LoadableComponent} />

webpack 會自動拆分 chunk,首屏渲染時,只會加載對應的 chunk,提高了渲染速度。

按需打包 mement、lodash、antd#

moment、lodash、antd 是使用頻率很高的第三方庫,但是庫本身的體積很大,專案中又不會用到全部的功能,全部引入會造成打包後的體積過大。

antd 可以使用 babel-plugin-import 來進行按需加載,只需要安裝 babel-plugin-import 然後配置.babelrc 文件:

{
  "plugins": [
    [
      "import", {
        "libraryName": "antd",
        "style": true
      }
    ]
  ]
}

babel-plugin-import 目前已經可以使用於 antd、antd-mobile、lodash 等庫。
lodash 也可以使用 babel-plugin-import 來進行按需加載,也可以使用 babel-plugin-lodash 來按需加載 lodash。

 npm i --save lodash
 npm i --save-dev babel-plugin-lodash @babel/cli @babel/preset-env
// .babelrc
{
  "plugins": ["lodash"],
  "presets": [["@babel/env", { "targets": { "node": 6 } }]]
}

moment 會將所有本地化內容和核心功能一起打包,打包出來的 moment 依賴包括了許多不需要的 locale 文件。因此我們需要對 moment 的 locale 文件進行按需打包。

你可以使用 IgnorePlugin 在打包時忽略本地化內容:

new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/);

也可以使用 webpack 的上下文替換插件 (ContextReplacementPlugin),允許覆蓋查找規則,通過正則篩選指定的文件。

只需要在 webpack 的配置文件 plugins 處增加如下代碼即可:

plugins: [
  new webpack.ContextReplacementPlugin(
    /moment[/\\]locale$/,
    /zh-cn/,
  ),
],

這裡通過正則匹配了 moment/locale 下的名為 zh-cn 的文件。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。