tree shaking 依赖 es module 的静态分析,commonjs 无法摇动;需确保第三方库提供 esm 入口、避免对象导出、正确配置 sideeffects 字段,并警惕动态 import、export *、全局赋值等失效场景。

Tree Shaking 不是靠画图运行的,但用思维导图梳理它,能帮你快速抓住主线、避开常见误区。核心不在于图形多精美,而在于逻辑是否闭环、关键约束是否标清。
核心前提:必须用 ES Module
Tree Shaking 的基础是静态可分析性。只有 import/export 语法才能在构建时确定依赖关系;require/module.exports 是运行时才决定引入什么,构建工具“摇不动”。
- 项目里混用 CommonJS(比如直接 require 第三方库的 cjs 版本),对应模块整体会被保留
- 第三方库若未提供 ESM 入口(即 package.json 中缺少
"module"字段),Webpack 默认 fallback 到 cjs,tree-shaking 失效 - 自己写的工具模块,务必用
export function xxx,避免export default { a, b }这种对象导出——它会阻碍按需引入
关键开关:sideEffects 字段
Webpack 靠 package.json 中的 "sideEffects" 字段判断哪些文件可以安全剔除。默认值是 true,意味着“所有文件都有副作用,一个都不能删”。
- 设为
false:告诉 Webpack “本包所有模块都是纯的”,只要没被 import 就可删 - 设为数组,如
["*.css", "src/init.js"]:只保留列表里的文件,其余全可摇 - 漏配或错配 sideEffects,会导致样式丢失、polyfill 不执行、全局变量未初始化等问题
常见失效场景(导图里建议单列“雷区”分支)
很多开发者开了 production 模式、用了 TerserPlugin,却仍摇不掉代码,问题往往出在这几处:
-
动态 import():比如
import(`./pages/${name}.js`),路径不确定,无法静态分析,整个目录可能被打包 -
export * from:聚合导出(如 index.js 中
export * from './a'; export * from './b')会让构建器难以追踪具体使用了哪些成员 -
赋值给全局对象:如
window.utils = { debounce },即使 debounce 没被直接 import,Webpack 也不敢删(怕破坏全局挂载) -
无引用但有副作用的导入:如
import './polyfill.js'或import './theme.css',它们没导出东西,但执行即生效——必须靠 sideEffects 显式声明
验证是否生效的实操方式
别只看 bundle 大小,要确认“删的是真没用的代码”:
- 用 Webpack Bundle Analyzer 查看产物中某个模块是否完整存在,还是只剩几个函数
- 在源码里加个明显标识(比如
console.log('never called')),再检查最终 JS 里还有没有这行 - 开启
optimization.providedExports: true和usedExports: true(Webpack 5+ 默认启用,但调试时可显式打开)











