Skip to content

Tree Shaking 生效要满足什么? ​

Tree shaking 是打包器根据 ESM 的静态结构,去掉没有被用到的导出。它主要发生在生产构建。模块如果在导入时就有副作用,打包器必须把这份模块留下,除非包作者声明没有副作用。

原理 ​

从入口的 import 出发,能走到的导出留下,走不到的函数和常量可以从产物里删掉。压缩器再去掉因此变得不可达的代码。开发构建为了编译速度和更清晰的堆栈,通常不做这一步。

这些情况会让摇树失效:

  • 依赖是 CommonJS,或者被编译器转成了 require。
  • 用变量动态访问导出,打包器无法知道运行时会用哪一个。
  • 模块顶层有必须执行的代码。package.json 的 "sideEffects": false 告诉打包器:这个包的模块没有「导入即发生」的副作用,没被用到就可以整文件丢弃。
  • CSS 文件属于有副作用的导入。如果包里有样式,要把样式路径标成有副作用,不能一刀切 false 把样式也摇掉。
json
{
  "sideEffects": ["**/*.css"]
}

库作者要提供 ESM 入口,避免在包的入口文件里把所有函数都执行一遍。调用方按名字导入,而不是为了方便拿整个命名空间却只用其中一个。

追问 ​

sideEffects: false 写错了会怎样?

顶层注册了全局组件、补丁或样式,结果被整文件删掉,线上表现为功能随机消失。这个字段是给打包器的承诺,承诺错了产物就是错的。

和按需加载是一回事吗?

不是。摇树减少单个包里的死代码。代码分割决定用户在哪一次导航才下载某一块。两者一起做,首屏才会变小。见 加载优化。

易错点 ​

  • 生产包变小了,不一定是摇树,也可能是压缩或依赖根本没被引用。用包分析确认某个导出真的消失。
  • Babel 如果把模块编成 CommonJS,后面的打包器就失去了静态结构。要保留 ESM。
  • 开发环境看到完整依赖,不能说明生产包也包含它们。

相关 ​