Tree Shaking 是基于 ES 模块静态分析的构建时优化技术,仅移除未被 import 引用且无副作用的导出代码;它依赖 import/export 语法、生产模式、无副作用声明及工具链不转译为 CommonJS。

Tree Shaking 不是“删掉没调用的函数”这么简单,而是基于 ES 模块静态结构,在构建阶段做依赖图分析和导出使用标记,只移除确定未被引用、且无副作用的代码。
核心原理:为什么只能在 ES Module 下工作?
ES Module 的 import/export 是静态语法,编译时就能确定谁导入了什么、谁导出了什么;而 CommonJS 的 require 是运行时动态执行的,Webpack 无法在打包前判断某段代码会不会被用到。所以开启 Tree Shaking 的前提必须是:源码用 export / import,且构建工具(如 Webpack)没有把模块转成 CommonJS 形式(比如 Babel 默认会把 export 转为 module.exports,这就断掉了 Tree Shaking 链路)。
常见失效原因与对应解法
Tree Shaking 失效往往不是配置问题,而是代码写法或工具链干扰:
- 用了
import _ from 'lodash'全量引入 → 改成具名导入import { debounce } from 'lodash'或路径导入import debounce from 'lodash/debounce' - Babel 把 ES Module 编译成了 CommonJS → 在
.babelrc中设置"modules": false,让 Babel 不处理模块语法,交由 Webpack 处理 - 模块有副作用(比如执行了全局注册、修改了原型、发了请求)→ 在
package.json中声明"sideEffects": ["*.css", "*.scss"],或设为false(表示无副作用,可安全摇) - 导出但没被任何 import 引用,比如
export { default as Button } from './Button'却没人 import Button → 这类 re-export 会被标记为unused harmony export并删除
如何验证是否生效?
不用靠猜,直接看产物和 Webpack 构建日志:
- 启用 Webpack 的
stats: "verbose",构建后搜索unused harmony export,看到这类提示说明 Tree Shaking 已介入 - 用
source-map-explorer可视化分析 bundle,确认像math.js中的subtract函数是否真的没出现在最终代码里 - 对比开启/关闭
optimization.usedExports: true后的打包体积差异(通常能减少 10%–30%,尤其在大量使用工具库时)
面试加分点:它和 Dead Code Elimination 的区别
Tree Shaking 是 Dead Code Elimination 的一种,但特指基于 ES 模块依赖图的导出级删减;而 DCE 更宽泛,比如 UglifyJS/Terser 做的是语句级、变量级的运行时不可达代码删除(如 if (false) {...})。两者常配合使用:Tree Shaking 先筛掉整个未引用的函数/模块,Terser 再压缩剩余代码里的冗余逻辑。


















