Tree Shaking 需避免对象式默认导出、命名空间导入、冗余解构及入口副作用;应使用具名导出、显式导入、精简解构和纯导出入口。

Tree Shaking 不是自动生效的魔法,它对代码写法非常敏感。很多看似合理、甚至“更简洁”的写法,恰恰会切断静态分析链路,让整块代码被保留——这就是反模式。规避的关键不是记住所有坑,而是理解“什么会让工具无法确定某段代码是否真没用”。
避免对象式默认导出
把多个函数塞进一个对象再 default 导出,是最常见的反模式:
- ❌ export default { add, subtract, multiply }; —— 即使用户只写
import { add } from './math',打包工具仍可能保留整个对象,因为obj.add是运行时属性访问,无法 100% 确保subtract没被其他方式间接调用 - ✅ 改为具名导出:export function add() {}、export const multiply = () => {} —— 每个导出独立可标记,工具能精准识别未引用项
禁用命名空间导入(import * as)
这种写法等于告诉构建工具:“我可能会用到这个模块里的任何东西”,直接关闭摇树路径:
- ❌ import * as utils from './utils'; utils.formatDate(); —— 即使只调用一个方法,
utils对象及其全部属性都会被保留 - ✅ 显式列出所需项:import { formatDate, parseISO } from './utils'; —— 工具只追踪这两个标识符,其余导出可安全剔除
- ⚠️ 注意:如果只是想做类型导入或副作用触发(如加载样式),应改用无绑定导入:import './styles.css';,并确保它被正确列入
sideEffects
慎用解构导入中的“冗余声明”
解构本身不破坏 Tree Shaking,但声明了却不用,可能在某些旧版或配置松散的环境中干扰判断:
- ❌ import { add, subtract, multiply } from './math'; add(1, 2); ——
subtract和multiply虽未调用,但出现在解构中,部分工具会保守保留(尤其搭配 Babel 转译时) - ✅ 只导入真正需要的:import { add } from './math'; —— 干净、明确,无歧义
- ? 小技巧:若需动态选择,可用具名导入 + 条件逻辑,而非一次性解构全部
警惕副作用隐性污染入口文件
类库或工具模块的主入口(如 index.js)一旦执行副作用,整个模块会被视为“不可摇”:
- ❌ 在入口文件里写:console.log('lib loaded');、window.MyLib = {};、import './polyfill.js'; —— 这些都会让 Webpack 认为该模块有副作用,拒绝剔除任何导出
- ✅ 入口只做导出:export { add, subtract } from './math'; —— 纯转发,无执行
- ✅ 副作用功能拆到子模块:import 'my-lib/init'; // 用户显式调用,并在
package.json的sideEffects中精确声明该文件


















