Tree Shaking 能真正减小体积的关键在于构建工具能否静态识别未使用导出,需从代码写法(推荐具名导出)、导入方式(避免默认/星号导入)、产物验证(检查report或bundle分析)及第三方库ESM支持四方面协同落实。

Tree Shaking 能否真正减小体积,关键不在于“有没有 import/export”,而在于构建工具能否准确识别哪些导出被使用、哪些是冗余的。评估 ES 模块导出方式对体积的影响,要从代码写法、工具行为和产物验证三个层面入手,缺一不可。
看导出形式是否支持静态识别
构建工具只对具名导出(named export)做精细剔除,对 default export 或对象聚合导出基本无能为力。
- ✅ 推荐写法:每个功能单独导出,如
export function debounce() { }或export const API_URL = '...' - ❌ 风险写法:用对象统一导出,如
export default { debounce, throttle }—— 整个对象可能被全量保留 - ⚠️ 注意:即使写了
export default class Utils,只要没被 import,通常也能被摇掉;但若 default 导出里包含副作用逻辑(如立即执行的初始化),就可能保留在 bundle 中
查导入方式是否触发精准引用
导入写法直接决定 Tree Shaking 的粒度。工具只能根据 import 语句反向追踪,哪些导出被“显式点名”了。
- ✅
import { debounce } from 'lodash-es'→ 只需保留debounce,其他函数可剔除 - ❌
import _ from 'lodash'→ CommonJS 全量导出,无法分析,整个库进包 - ⚠️
import * as utils from './utils'→ 工具无法判断后续是否通过utils[key]动态调用,整模块视为“被引用”,无法摇树
验构建产物是否真实剔除未用代码
不能只看配置开了没,必须检查最终生成的 JS 文件或依赖图,确认未使用的导出确实消失了。
立即学习“Java免费学习笔记(深入)”;
- 在 Vite 中运行
vite build --report,打开 report.html,搜索某个明确未使用的函数名,看它是否出现在任何 chunk 的依赖列表中 - 在 Webpack 中启用
stats: 'verbose'或使用webpack-bundle-analyzer,观察模块的 “provided exports” 和 “used exports” 是否匹配 - 手动在源码中加一行
import { unusedHelper } from './helpers'(但不调用),再构建,对比体积变化——若体积不变,说明该导出已被成功摇掉
盯第三方库是否真正提供 ESM 入口
你自己写得再规范,如果依赖的库本身不是 ESM,Tree Shaking 就无从谈起。
- 检查
node_modules/xxx/package.json是否有"type": "module"、"exports"或"module"字段 - 优先选用
lodash-es替代lodash,date-fns替代moment,它们都按函数粒度导出,且 package.json 明确声明 ESM 入口 - 避免使用仅提供 UMD 或 IIFE 版本的传统库,除非搭配插件(如
unplugin-auto-import)实现模拟摇树


















