构建支持 Tree-Shaking 的 JavaScript 库需遵循以下核心步骤:使用 ES6 模块语法、配置打包工具输出 ESM 格式、声明模块入口及副作用标识,并确保模块纯净无副作用。
一、使用 ES6 模块语法导出功能Tree-Shaking 依赖静态模块结构,需通过 import/export 语法实现。
- 按名称导出:每个功能单独导出,避免默认导出或动态导出(如 export default 或 export { ... } from ...)。// utils/math.jsexport const add = (a, b) => a + b;export const subtract = (a, b) => a - b;// index.jsexport { add } from './utils/math';export { formatPrice } from './utils/string';
- 避免副作用:不要在模块顶层执行可观察的操作(如修改全局变量、绑定事件、直接调用函数),否则会阻止未使用代码的移除。
二、配置打包工具(以 Rollup 为例)Rollup 原生支持 Tree-Shaking,需生成 ESM 格式并处理外部依赖。
- 输出格式:设置 format: 'es' 保留模块结构。
- 外部化依赖:通过 external 排除第三方库(如 lodash),避免其被打包进最终产物。// rollup.config.jsexport default { input: 'src/index.js', output: { dir: 'dist', format: 'es' }, external: ['lodash'] // 外部化依赖};
- 多格式输出:若需兼容 CommonJS,可同时生成 cjs 格式,但需通过 package.json 区分模块类型。
三、声明模块入口及副作用标识在 package.json 中指定模块入口和副作用信息,帮助构建工具识别 Tree-Shaking 兼容性。
- 模块入口字段:
main:指向 CommonJS 版本(兼容旧环境)。
module:指向 ES 模块版本(用于现代工具如 Webpack/Rollup)。
{ "main": "dist/index.cjs", "module": "dist/index.js"} - 副作用声明:
sideEffects: false:表示整个库无副作用,允许安全移除未引用代码。
若存在副作用(如 CSS 文件或全局事件监听),需明确列出相关文件路径:
{ "sideEffects": [ "*.css", "src/utils/event-listener.js" ]}
四、避免副作用,保持模块纯净- 错误示例:顶层执行副作用操作(如日志、事件绑定)会破坏 Tree-Shaking。// 错误:顶层副作用console.log('Library loaded'); // 副作用window.addEventListener('error', handler);export const foo = () => {};
- 正确做法:将副作用封装在函数内,由用户显式调用。// 正确:副作用由用户触发export const initLogger = () => { console.log('Library initialized');};export const addEvent = (type, handler) => { window.addEventListener(type, handler);};
五、验证 Tree-Shaking 效果总结构建支持 Tree-Shaking 的库需满足以下条件:
- 模块语法:使用静态 import/export,避免动态导出或默认导出。
- 打包配置:生成 ESM 格式,外部化依赖,排除非必要代码。
- 包配置:通过 module 和 sideEffects 字段明确模块类型及副作用。
- 代码纯净:封装副作用逻辑,避免顶层可观察操作。
遵循以上规范后,库的未使用代码可被现代构建工具安全移除,显著优化最终产物体积。