核心是子包必须声明exports+type:"module",确保ESM静态可分析;需显式定义子路径入口、具名导出、精确sideEffects声明,并引导用户子路径导入。

在组件库开发中实现最大化 Tree Shaking,核心不是“开启某个开关”,而是让每个子模块都满足 ESM 静态可分析的前提,并确保构建产物与消费方式严格匹配。Vite 或 Rollup 本身默认支持摇树,但真正决定能否摇掉代码的,是你的包如何导出、如何被引用。
子包 package.json 必须声明 exports + type: "module"
这是最关键的一步。仅靠 main 或 module 字段已不够健壮,exports 才是现代包的标准入口控制方式:
- 设置 "type": "module":强制所有 .js 文件按 ESM 解析,避免 export 被当成 CommonJS 忽略
- 用 exports 显式定义不同导入路径对应的 ESM 入口,例如:
"./button": { "import": "./dist/button.es.js" },这样用户import Button from '@ui/button'才能精准命中单个组件的 ESM 文件,而非整个包的 index - 避免只写 main(指向 CJS)或只写 module(已被 exports 取代),否则工具可能退化到加载全量 CJS 包
构建输出必须为标准 ESM 格式且具名导出
Vite 库模式(build.lib)需明确配置,不能依赖默认行为:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 指定 formats: ['es'](若只需前端使用)或 ['es', 'cjs'](兼顾 Node),但确保 es 输出是真正可摇的
- 入口文件(如 src/index.ts)不要用
export * from './button'这类模糊重导出,改用显式具名导出:export { Button } from './button' - 禁用
rollupOptions.output.preserveModules: true,它会保留原始目录结构,破坏跨文件的死代码判断
用户侧 import 方式要配合子路径导入
摇树效果最终取决于调用方怎么引入。即使你包配置完美,用户仍写 import { Button, Icon } from '@my-ui',那还是得加载整个 index.es.js:
立即学习“Java免费学习笔记(深入)”;
- 文档中主推子路径导入:
import Button from '@my-ui/button',并确保该路径在 exports 中有独立声明 - 提供 babel-plugin-import 或 Vite 插件支持按需导入语法(如
import { Button } from '@my-ui'自动转为子路径),但底层仍依赖 exports 的精确映射 - 避免在包根 index 中聚合导出所有组件(
export * from './button'; export * from './icon'),这会让摇树退化为“整包存活”
标记 sideEffects 以辅助全局副作用识别
某些文件虽无导出,但有执行副作用(如样式注入、polyfill 注册),需显式声明,否则会被误删:
- 在子包 package.json 中设 "sideEffects": ["./dist/*.css", "./dist/*.js"],或更细粒度地只列真正有副作用的文件
- 纯逻辑组件(如 utils、hooks)可设 "sideEffects": false,让构建器放心删除未引用部分
- 注意:这个字段对 Vite 的影响弱于 Webpack,但它仍是通用提示,尤其在 Monorepo 多包联动时有用

















