组件库打包与按需加载
组件库打包与按需加载
这篇笔记还在编辑中,内容可能会继续补充、调整或重写。
从消费者环境出发
组件库不是必须同时输出 ESM 和 CJS。模块格式应由消费者决定:现代 bundler 项目通常可以只消费 ESM;仍需支持旧 Node.js、CommonJS 工具或特定测试环境时,才考虑双产物及其额外验证成本。
双产物可能产生同一个包被加载两次、默认导入语义不同或状态不共享等 dual-package hazard。发布前必须在真实消费者环境验证,不能只确认包自身能够构建。
设计发布入口
使用 package.json 的 exports 明确公共入口,阻止消费者依赖内部文件:
{
"name": "@example/ui",
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./button": {
"types": "./dist/button.d.ts",
"import": "./dist/button.js"
},
"./style.css": "./dist/style.css"
},
"files": ["dist"]
}
如果确实输出 CJS,再增加经过验证的 require 条件。不要让 main、module、exports 和类型入口分别指向语义不同的实现。
按需加载成立的条件
- 入口与子路径使用静态 ESM 导出
- 组件之间没有隐藏的全局注册
sideEffects正确保留必要的 CSS 和初始化代码- 框架、渲染器等宿主依赖声明为合理的 peer dependency
- 每个入口的类型和样式都能独立解析
按需加载最终要通过消费应用的产物图验证。仅仅提供 import { Button } 语法,不代表未使用组件一定会被删除。
类型声明
类型声明必须与实际 JavaScript 入口一一对应。库的模块解析规则可能与应用 bundler 不同,尤其要验证 Node.js nodenext 消费者、bundler 消费者和声明文件中的相对导入。
消费者测试
发布前先生成 tarball,并在至少两个最小项目中安装:
- 当前支持的主流 bundler 应用
- 声明的最低 Node.js、TypeScript 和框架版本组合
执行类型检查、单元测试和生产构建,检查包中实际发布的文件,而不是工作区源码别名。
验收标准
-
exports只暴露承诺维护的公共入口 - ESM/CJS 策略有明确消费者依据
- 未使用组件不会进入消费应用产物
- 必要 CSS 不会被错误 Tree Shaking
- 框架依赖不会在消费应用中重复打包
- tarball 消费测试覆盖类型、样式和生产构建