Tree Shaking 高效依赖 ESM 纯净性、精准 sideEffects 声明及按需导入;混入 CommonJS、副作用未声明或全量导入均导致失效,须用 source-map-explorer 和 stats 验证。

掌握 Tree Shaking 的高级进阶技巧,关键不在“配对开关”,而在理解它如何被代码结构、模块语义和构建链路共同约束。真正起效的不是配置本身,而是你写的每一行 import 和每个 export 所传递的静态意图。
确保模块系统完全纯净(ESM-only)
Tree Shaking 不会跨模块边界“猜”行为,它只信任静态可分析的 import/export。一旦混入 CommonJS,整条依赖链就可能失效。
- 检查所有自定义模块:禁止在同一个文件里同时出现
module.exports = {...}和export function foo() - 排查 node_modules:运行
npx depcheck --ignores=webpack,terser查看是否引入了仅提供 CommonJS 的库(如老版本moment、uuid@3) - 若必须用非 ESM 库,优先选官方 ESM 分支(如
uuid@9+默认导出 ESM),或通过exports字段声明入口:"exports": {".": "./dist/esm/index.js"}
精准控制副作用边界
Webpack 不敢删掉“可能有副作用”的模块——哪怕你只用了其中一行函数。sideEffects 字段不是可选项,而是你向构建工具发出的明确契约。
使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景: (1) 暂存更改时需要提交信息; (2) 审查 diff 时希望获得结构化摘要; (3) 编写 PR 描述或变更日志(changelog)条目; (4) 用户明确要求“为本次更改编写提交信息”。 该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。
- 全局无副作用时,直接写
"sideEffects": false(适用于纯工具函数库) - 有副作用但可控时,精确列出路径:
"sideEffects": ["./src/polyfill.js", "./styles/**/*.css"],避免通配符误伤 - 切勿在工具模块顶部写
import './reset.css'或require('regenerator-runtime')—— 这会让整个模块被锁定保留
导入方式决定摇得动不动
Webpack 的标记逻辑非常直接:它只看你 import 了什么名字,不看你“本意”想用什么。
- 禁用
import * as utils from './utils':这种写法等于告诉 Webpack “我要全部” - 避免默认导入全量包:
import _ from 'lodash'→ 改为import debounce from 'lodash-es/debounce' - 对支持命名空间但又需按需的库(如
date-fns),坚持用具名导入:import { format, parseISO } from 'date-fns',而非import format from 'date-fns/format'(后者虽可行,但破坏统一风格且易遗漏)
验证不是走形式,而是闭环反馈
不验证的 Tree Shaking 就像没关水龙头就擦地板。体积数字不会说谎,但得知道怎么看。
- 用
source-map-explorer dist/static/js/main.*.js直观查看 lodash-es 中实际打进去了哪些函数 - 开启 Webpack stats:
stats: 'verbose',搜索unused harmony export确认未使用导出是否真被标记 - 对比构建产物:执行
npm run build && ls -lh dist/static/js/,观察体积变化是否与预期导入项数量匹配(例如只引入 2 个函数却比之前大 100KB,大概率有副作用或导入方式问题)

















