
确保大型项目中 Tree Shaking 真正生效,关键不是“开了没开”,而是整条链路是否都满足静态分析前提——从代码写法、依赖选型到构建配置,缺一不可。实际项目里体积没降,往往不是工具不行,而是某处悄悄破坏了静态性。
坚持顶层静态导入导出
Tree Shaking 的基础是编译时可确定的依赖关系。任何把 import/export 放进条件、循环、函数或 try/catch 里的写法,都会让构建工具失去分析能力。
- ✅ 正确:在模块最外层写 import { throttle } from 'lodash-es'
- ❌ 错误:if (DEBUG) import('./debug-tools') 或 const utils = require('./utils')
- ⚠️ 注意:import() 是动态加载,返回 Promise,它引入的模块不参与 Tree Shaking
精准使用 ESM 兼容的第三方库
即使你代码写得再规范,如果引入的库本身是 CommonJS 格式(比如用 require 导出),或者主入口是聚合式导出(如 export *),Tree Shaking 就会失效。
- 优先选用明确支持 ESM 的版本:用 lodash-es 替代 lodash,用 date-fns/format 替代 date-fns 全量导入
- 检查库的 package.json 是否有 "module" 字段,指向 .mjs 或 ES 模块入口
- 避免 import * as xx 或默认导入整个包,这类写法会让构建工具无法判断哪些子功能真正被用到
显式声明副作用,避免保守保留
有些文件(比如全局样式注入、polyfill、初始化脚本)虽然没被直接 import 引用,但执行就有影响。构建工具为防误删,会默认保留所有未引用模块——除非你告诉它哪些可以安全剔除。
- 在项目根目录 package.json 中设置:"sideEffects": false(表示绝大多数文件无副作用)
- 若部分文件确实有副作用(如 src/styles/index.css、src/init.js),则写成数组形式:"sideEffects": ["*.css", "src/init.js"]
- 这个字段对 node_modules 中的依赖也起作用,尤其在 Vite 和 Webpack 5+ 中影响显著
只在生产构建后验证效果
开发模式下看到的 bundle 并不能反映 Tree Shaking 结果——HMR、source map、devtool 配置都会干扰体积判断。
- 运行真实构建命令:npx webpack --mode=production 或 vite build
- 用 rollup-plugin-visualizer 或 source-map-explorer 打开生成的 .js 文件,直接查看某个函数是否还在产物中
- 关注打包统计中的 provided exports 字段,确认未被引用的导出是否被标记为 “unused”










