Tree-shaking 起作用需满足三条件:库为 ESM 格式(如 lodash-es)、精准具名导入或子路径导入、构建工具配置支持深度分析;避免默认/通配符/动态导入。

要让 Tree-shaking 真正起作用,关键不是“写了 import { debounce }”,而是整个导入链都得支持静态分析——第三方库本身得是 ESM 格式、导出方式得干净、你写的引入方式也得精准。
用对库版本:优先选 lodash-es 而非 lodash
原版 lodash 是 CommonJS 发布的,即使你写 import { debounce } from 'lodash',构建工具也无法静态判断哪些导出被用到,最终仍会打包整个库。而 lodash-es 是纯 ESM 版本,每个函数单独导出,没有聚合入口,天然适配 Tree-shaking。
- ✅ 正确:
import { debounce } from 'lodash-es' - ❌ 无效:
import { debounce } from 'lodash'(CJS 格式,摇不动) - ? 验证方法:查该库
package.json是否有"module"字段或"type": "module",且主入口是.mjs或明确指向 ESM 文件
走子路径导入:绕过聚合导出陷阱
有些库虽标称支持 ESM,但主入口仍用 export * 或动态导出(比如 Object.keys(...).forEach),这会让构建工具放弃静态分析。直接导入具体文件路径,能彻底跳过这类问题。
- ✅ 推荐:
import debounce from 'lodash-es/debounce'或import format from 'date-fns/format' - ⚠️ 注意:
import { format } from 'date-fns'看似一样,但实际会经过主入口中不纯的导出逻辑,可能带入未用代码 - ? 原理:子路径导入对应单个模块文件,无副作用、无条件分支、导出确定,Tree-shaking 可安全剔除其余部分
配置层面补位:让构建工具信任并深入分析
即使代码写对了,构建工具默认也可能保守处理第三方依赖。需主动引导它做深度摇树。
- Webpack:确保
mode: 'production',开启optimization.usedExports: true,并在package.json中为所用库声明"sideEffects": false(或精确列出有副作用的文件) - Vite:默认对
node_modules中标记sideEffects: false的包做深度摇;若用的是未声明该字段的库,可通过optimizeDeps.include强制预构建其 ESM 版本 - 别名映射(可选):在 Webpack 的
resolve.alias中把lodash指向lodash-es,避免团队误引旧版
警惕动态行为和默认导入
任何破坏静态可分析性的写法都会让 Tree-shaking 失效。
- ❌ 避免:
import _ from 'lodash-es'(默认导入 → 整个命名空间被保留) - ❌ 避免:
import * as _ from 'lodash-es'(通配符导入 → 构建工具无法判定使用边界) - ❌ 避免:
if (condition) import('./utils')(动态 import → 不参与摇树,只做代码分割) - ✅ 安全写法:始终用具名导入 + 明确路径 + ESM 库,保持导入语句在顶层作用域


















