我理解的 sideEffects

1,243 阅读1分钟

理解 sideEffects是什么 ,需要有一些前置知识, 那就是 webpack 的 tree shaking 以及 ESM 模块的 import , export

webpack 4添加了 sideEffects , 在 package.json 中添加这个属性, 表示, 哪些模块是 纯的ES6 模块, 当代码未被使用, webpack可以被删除

基于 ESM 模块的项目, 很轻松的能分析到, 哪些文件是未使用的, 可以轻松 树摇掉的, 但是项目中没办法达到这种纯度, 所以,可以通过如下的方式,告知 webpack 怎么处理未使用的代码

1、 直接在 package.json 中配置 sideEffects 为 false ,告知webpack 所有代码都没有副作用, 可以安全的删除

{
  "name": "webpack 测试sideEffects 删除未使用的代码",
  "sideEffects": false
}

2、如果代码里有副作用, 不希望webpack 比较果断的tree shaking , 我们通过给 sideEffects 配置一个数组, 告知webpack 哪些文件是 有副作用的, 不要tree shaking 掉

{
  "name": "webpack 测试sideEffects 删除未使用的代码",
  "sideEffects": [
     "./src/some-side-effectful-file.js",
    "/src/main.js",
    "/\.css$/"
  ]
}

数组支持: 相对路径, 绝对路径, 还有 glob 模式

场景

webpack.config.js

const path = require("path")
const {CleanWebpackPlugin} = require("clean-webpack-plugin")

module.exports = {
  mode: "production",
  entry: {
    app: path.resolve("./src/main.js")
  },
  output: {
    filename: "[name].bundle.js",
    path: path.resolve(__dirname, "dist"),
    publicPath: "/"
  },
  plugins: [
    new CleanWebpackPlugin()
  ]
}

package.json

{
  "main": "index.js",
  "scripts": {
    "build": "webpack"
  },
  "devDependencies": {
    "clean-webpack-plugin": "^4.0.0",
    "webpack": "^5.72.0",
    "webpack-cli": "^4.9.2"
  }
}

目录结构

- src
  - lib.js
  - main.js
- package.json
- webpack.config.js

场景1

main.js

这里只引入一个, 看看打包后的结果

import {add} from "./lib"

/**
 * 场景1:这里只引入一个, 看看打包后的结果
 * 结果: 只有打包后的运行结果  console.log(3)  直接给静态分析出来了
 */

console.log(add(1, 2))

lib.js

/**
 * 导出2个工具函数
 */

export function add (a, b) {
  return a + b
}

export function div (a, b) {
  return a / b
}

npm run build 查看打包结果

(()=>{"use strict";console.log(3)})();

只有打包后的运行结果 console.log(3) 直接给静态分析出来了 , div 被 tree shaking 了

场景2

main.js

import {add} from "./lib"

/**
 * 场景2:这里只引入一个,add 但是不调用, add 在 lib中执行过
 * 结果: console.log(3)  也是直接执行了
 */

lib.js

/**
 * 导出2个工具函数
 */

export function add (a, b) {
  return a + b
}

export function div (a, b) {
  return a / b
}

// 场景2: 在这里执行了, 看打包后的产物
console.log(add(1, 2))

npm run build 打包后的产物

(()=>{"use strict";console.log(3)})();

场景3

{
  "name": "webpack 测试sideEffects 删除未使用的代码",
  "sideEffects": false
}

main.js

import {add} from "./lib"
/**
 * 场景3:这里只引入一个,add 但是不调用, add 在 lib中执行过, 在 package.json中添加了sideEffects: false
 * 结果:打包后的产物, 什么都没有, 认为 add 是无副作用的,直接给 tree shaking 了
 */

lib.js

/**
 * 导出2个工具函数
 */

export function add (a, b) {
  return a + b
}

export function div (a, b) {
  return a / b
}

// 不管这里执行还是不执行, 由于在 main.js 中只引入没有执行,所以webpack 认为是无副作用
// 直接移除了
console.log(add(1, 2))

app.bundle.js 中什么都没有, 空的

场景4

css文件通过 import 的方式引入, 应该是当做有副作用的文件, 不能被 tree shaking 的, 所有要指定package.json

文件结构

- src
    - app.css
    - lib.js
    - main.js
- webpack.config.js
- package.json

main.js

import {add} from "./lib"
import "./app.css"

webpack.config.js

const path = require("path")
const { CleanWebpackPlugin } = require("clean-webpack-plugin")

module.exports = {
  mode: "production",
  entry: {
    app: path.resolve("./src/main.js")
  },
  output: {
    filename: "[name].bundle.js",
    path: path.resolve(__dirname, "dist"),
    publicPath: "/"
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: "css-loader"
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin()
  ]
}

package.json

{
  "main": "index.js",
  "scripts": {
    "build": "webpack"
  },
  "sideEffects": [
    "./src/app.css"
  ],
  "devDependencies": {
    "clean-webpack-plugin": "^4.0.0",
    "css-loader": "^6.7.1",
    "webpack": "^5.72.0",
    "webpack-cli": "^4.9.2"
  }
}

打包后的产物,包含 css 符合期望, 如果不设置 sideEffects , 会导致 webpack 认为 css 无副作用, 直接被 tree shaking 掉

image.png

结语

sideEffects 就是为 tree shaking 服务的, 所以

  • 使用 ES2015 模块语法 - 写你的项目
  • 在项目的package.json 文件中,添加 sideEffects