CodeWalk

Webpack Tree Shaking原理与sideEffects

作者:编译有声 · 2026-05-30 12:55

解释Webpack Tree Shaking(摇树优化)的原理、必要条件,以及package.json中sideEffects字段的作用。为什么Tree Shaking对CommonJS模块无效?如何正确配置以实现最大优化效果?

回答

编译有声

Tree Shaking原理

Tree Shaking依赖ES Module静态分析能力——import/export在编译时确定,而非运行时。

工作流程:

  1. 标记阶段(Webpack标记未使用导出):
    • Webpack遍历模块的AST,标记每个export是否被其他模块引用
    • 未被引用的export标记为/* unused harmony export */
  2. 移除阶段(TerserWebpackPlugin执行):
    • UglifyJS/Terser根据标记删除未使用的代码
    • 副作用安全的代码才可安全删除

必要条件:

// ❌ 破坏摇树的写法
import _ from 'lodash';       // 全量导入
require('module');           // CommonJS动态导入
import * as utils from 'utils'; // 命名空间导入

// ✅ 支持摇树的写法
import { debounce } from 'lodash-es';  // 具名导入
import isArray from 'lodash/isArray';  // 路径导入

sideEffects字段

{
  "sideEffects": false,  // 所有模块无副作用,可安全树摇
  "sideEffects": [       // 指定有副作用的模块
    "**/*.css",
    "./src/polyfill.js"
  ]
}
  • false:告知Webpack所有模块无副作用,未使用的export可安全删除
  • 数组:指定的文件有副作用(如CSS、polyfill),不会被移除
  • 不设置:所有模块默认被认为有副作用,Tree Shaking效果有限

为什么CommonJS无效?

const module = require('module');
  • require()是动态的,可以在条件语句中执行
  • module.exports可以随时修改
  • Webpack无法在编译时确定哪个属性被使用
  • 只能全量引入

最佳实践:

  1. 业务代码:配置sideEffects: false或具体列表
  2. 库代码:导出ES Module格式(package.json加"module":"dist/index.esm.js"
  3. lodash使用lodash-es代替lodash
  4. 使用babel时配置"modules": false避免转译import/export
  5. 启用optimization.usedExports: trueoptimization.sideEffects: true