webpack 4 新增 sideEffects 配置的做用和注意事項

原文連接: github.com/yinxin630/b…
技術交流羣: fiora.suisuijiang.com/css

在 webpack 2 版本, 增長了對 ES Module 的支持, 使得 webpack 可以分析出未使用的 export 內容, 而後將其 tree-shrking 掉webpack

可是模塊中那些具有反作用的代碼, webpack 會將其保留git

舉一個例子, 項目中存在 utils/a.js 模塊和 /utils/b.js 模塊, 並經過 utils/index.js 提供統一入口
其中 b 模塊包含一條打印語句, 是具備反作用的github

// utils/a.js
export function a() {
    console.log('aaaaaaaaaaaaa');
}

// utils/b.js
console.log('======== b.js ==========');
export function b() {
    console.log('bbbbbbbbbbbbbb');
}

// utils/index.js
export * from './a';
export * from './b';
複製代碼

添加主入口 app.js, 只引用 a 模塊, 咱們指望未使用的 b 模塊被 tree-shaking 掉web

// app.js
import { a } from './utils';
a();
複製代碼

咱們看一下打包後的結果, 注意要在 production 模式下打包. 結果以下所示, 我去掉了無關的 webpack 啓動代碼npm

// output
([
  function(e, t, r) {
 'use strict';
    r.r(t),
      console.log('======== b.js =========='),
      console.log('aaaaaaaaaaaaa');
  },
])
複製代碼

打包結果中, 不包含 b 模塊, 可是 b.js 中的反作用代碼被保留了, 這是合乎情理的json

sideEFfects 做用

下面修改下 b.js 的內容數組

// utils/b.js
Object.defineProperty(Array.prototype, 'sum', {
    value: function() {
        return this.reduce((sum, num) => sum += num, 0);
    }
})
export function b() {
    console.log([1, 2, 3, 4].sum());
}
複製代碼

咱們在 Array 原型鏈上定義了一個新方法 sum, 這是具備反作用的. 而後在 b 模塊中調用了該方法, 可是做爲 b 模塊的維護者, 我又但願 sum 是"純粹"的, 只被我使用, 外部並不依賴它的實現安全

修改 package.json, 新增字段 "sideEffects": false, 該字段代表整個工程是"無反作用"的
從新調用 webpack 編譯, 期待在 b 模塊沒被使用的狀況下, b 中定義的 sum 方法也被 tree-shaking 掉, 結果以下app

([
  function(e, t, r) {
 'use strict';
    r.r(t), console.log('aaaaaaaaaaaaa');
  },
])
複製代碼

如指望那樣, 整個 b 模塊都被 tree-shaking 掉了, 包括包含反作用的代碼

因此, sideEffects 能夠優化打包體積, 而且必定程度上能夠減小 webpack 對源碼分析過程, 加快打包速度

你能夠再試試引用 b 模塊、sideEffects 值設爲 true、去掉 sideEffects 等狀況的打包結果

sideEffects 配置

sideEffects 除了能設置 boolean 值, 還能夠設置爲數組, 傳遞須要保留反作用的代碼文件(例如: "./src/polyfill.js") 或者傳遞模糊匹配符(例如: "src/**/*.css")

sideEffects: boolean | string[]
複製代碼

sideEffects 注意事項

實際項目中, 一般並不能簡單的設置爲 "sideEffects": false, 有些反作用是須要保留的, 好比引入樣式文件

webpack 會認爲全部 import 'xxx' 語句是僅引入而未使用, 若是你錯誤的將其聲明成了"無反作用", 它們就會被 tree-shaking 掉, 而且因爲 tree-shaking 僅在 production 模式生效, 本地開發時可能一切還是正常的, 並不能及時發現問題

下面這些都是"僅引入而未使用"的例子

import './normalize.css';
import './polyfill';
import './App.less';
複製代碼

相應的, 下面這種就不算

import icon from './icon.png';
function Icon() {
    return (
        <img src={icon} /> ) } 複製代碼

這些有反作用的文件, 咱們要正確聲明, 修改 sideEffects 值

// package.json
"sideEffects": [
  "./src/**/*.css"
]
複製代碼

在使用中, 務必要正確設置 sideEffects 值

sideEffects 侷限性

sideEffects 配置是以文件爲維度的, 只要你配置了文件具有反作用, 即使你只用了該文件中沒有反作用的那部分功能, 仍然會將反作用保留

好比將 b.js 修改成

Object.defineProperty(Array.prototype, 'sum', {
    value: function() {
        return this.reduce((sum, num) => sum += num, 0);
    }
})
export function b() {
    console.log([1, 2, 3, 4].sum());
}
export function c() {
    console.log('ccccccccccccccccccc');
}
複製代碼

app.js 中僅引入 c 方法, b 方法會被 tree-shaking, 但 sum 方法不會

再談"反作用"的含義

初次看到 sideEffects 配置可能會很奇怪, 代碼明明是有反作用的, 爲何要聲明它是"無反作用"呢?

其實能夠換個角度來想, sideEffects 是通知 webpack 該模塊是能夠安全的 tree-shaking 的, 無需關心其反作用

後話

sideEffects 對 webpack 構建過程有着很大影響, 對開發 npm 模塊尤其重要. 使用中要特別注意聲明的正確性

相關文章
相關標籤/搜索