Tree Shaking 不会剔除含副作用的函数表达式,因其依赖“无副作用”前提;工具仅移除未引用且可证明无副作用的代码,副作用包括调用API、修改全局变量等,需通过模块拆分、sideEffects配置等方式源头隔离。

不能强制剔除含函数表达式副作用的代码片段——Tree Shaking 的前提正是“无副作用”,而函数表达式本身若产生副作用(如修改全局变量、调用 API、触发 DOM 变更等),工具会保守保留,这是设计使然,不是配置能绕过的。
理解副作用与 Tree Shaking 的边界
Tree Shaking 本质是静态分析:它只移除“未被引用且可证明无副作用”的导出与语句。一旦代码中出现以下任一情况,打包工具(Vite/Rollup/Webpack)就会将其标记为有副作用,跳过剔除:
- 直接调用函数(哪怕只是
console.log()或localStorage.setItem()) - 函数内修改外部变量(闭包变量、模块级变量、window 属性)
- 使用
try...catch、with、eval等动态语法 - 导出对象含方法或计算属性(如
export const utils = { log() { ... } })
真正可控的裁剪方式:从源头隔离副作用
与其试图“强制剔除”,不如让副作用代码不参与 Tree Shaking 分析范围。常用做法:
- 拆分模块职责:将纯计算逻辑(无副作用)单独抽成 ESM 模块,导出 const/函数;副作用操作(如请求、日志)放在另一模块,按需导入
-
标记副作用文件:在
package.json中设置"sideEffects": false(全局禁用),或显式列出含副作用的文件(如"sideEffects": ["./src/utils/logger.js"]) -
避免在导出语句中执行逻辑:错误写法
export const data = fetchData();→ 正确写法export const getData = () => fetchData();
Webpack 和 Rollup 的关键配置项
这些配置不改变“是否保留副作用”,但能提升裁剪精度:
-
Webpack:确保
optimization.usedExports: true+mode: 'production',并检查module.rules中 Babel 是否启用了modules: false(避免转成 CommonJS 破坏静态分析) -
Rollup / Vite(生产构建):默认启用严格 Tree Shaking;可在
rollupOptions.treeshake中设{ moduleSideEffects: 'no-unknown' },让未知模块(如未标注 sideEffects 的第三方库)不阻断剔除 -
注意 babel-plugin-transform-runtime:它可能注入辅助函数并产生隐式副作用,建议搭配
useESModules: true使用
验证是否生效的简单方法
不要依赖体积数字,直接检查产物:
- Vite:构建后查看
dist/assets/*.js,搜索未使用的导出名是否残留 - Webpack:启用
stats: 'verbose',观察usedExports字段是否为true,并在 bundle 分析器中确认未引用模块是否出现在 chunk 里 - Rollup:开启
treeshake: { logs: true },控制台会打印被剔除的语句
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/xinjizixun/123739.html