tree-shaking 失效主因是动态导入、条件导出、隐式副作用、commonjs 混入及开发配置不当;需坚持纯 esm、显式声明 sideeffects、禁用 babel 转译 export、确保生产模式构建。

Tree-shaking 失效,往往不是因为代码写得“不够函数式”,而是某些看似无害的写法或构建配置,悄悄切断了静态分析的路径。核心在于:Webpack 或 Rollup 依赖 ESM 的静态结构(如 import/export)来识别未使用导出;一旦出现动态、副作用或非标准引用,摇树就无法安全剔除。
动态导入或条件导出破坏静态可分析性
当模块加载路径、导出名或是否导出由运行时逻辑决定时,打包工具无法在构建期判断哪些代码会被用到。
- 避免
import(`./module-${type}.js`)这类动态导入(除非明确需要 code-splitting),它会让整个模块及其依赖逃逸 tree-shaking - 不要在
export前加条件判断,例如:
const utils = { a: () => 1, b: () => 2 };
if (process.env.NODE_ENV === 'dev') export const devUtils = utils;
这种写法让devUtils变成一个“可能存在的导出”,工具只能保守保留全部 - 推荐改为纯 ESM 风格:每个功能独立命名导出,按需引入,不包裹在对象或条件中
存在未声明的副作用(sideEffects: false 不生效)
即使你写了 "sideEffects": false,只要模块里有隐式副作用(如执行全局赋值、修改原型、发起请求),打包工具就必须保留整个模块——因为它不敢删“可能影响行为”的代码。
- 检查
node_modules中第三方库是否声明了sideEffects字段;没声明则默认视为有副作用,整包保留 - 自己写的工具模块,确保不带副作用:避免
window.xxx = ...、Array.prototype.xxx = ...、console.log()(尤其在顶层)、fetch()等 - 如有必要保留副作用,显式标注:
"sideEffects": ["*.css", "*.scss"],其余文件才可被安全摇掉
CommonJS 混入或 Babel 转译污染 ESM 结构
ESM 是 tree-shaking 的前提。若项目中混用 require() / module.exports,或 Babel 错误地将 export 编译为 Object.defineProperty(exports, ...),静态分析就会失效。
- 确认构建链路中 Babel 不处理 ESM 语法:设置
presets: [['@babel/preset-env', { modules: false }]],保留原生export - 避免在 ESM 模块中
requireCJS 模块(尤其是只取其中某个方法时),CJS 模块整体不可摇;优先使用已提供 ESM 版本的库(如 lodash-es 替代 lodash) - 检查
package.json中是否正确设置了"type": "module"或通过"exports"字段指向 ESM 入口
开发模式下未启用生产构建或未关闭 devtool
tree-shaking 是生产优化,开发环境下通常被禁用;且某些 source map 生成方式(如 eval、cheap-module-eval-source-map)会干扰模块图解析。
- 验证是否真在 production 模式运行:Webpack 的
mode: 'production'或 Rollup 的minify: true是前提 - 避免在生产构建中使用
devtool: 'eval'类型,改用'source-map'或'hidden-source-map' - 用
webpack-bundle-analyzer或rollup-plugin-visualizer查看实际产物,确认未使用导出是否真的消失,而非仅“看起来没调用”
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











