前端组件库工程化
覆盖组件 API、设计令牌、构建发布、类型声明、可访问性、测试和版本治理的组件库实践。
前端组件库工程化
本文聚焦组件库的可维护性、可访问性和发布治理。
1. 先定义组件库的边界
组件库同时服务三类消费者:业务开发者、设计系统维护者和最终用户。一个可长期维护的组件库至少要明确:
- 组件行为和状态:受控/非受控、键盘操作、表单校验和错误状态。
- 样式契约:颜色、间距、字号、圆角、层级等设计令牌,以及主题覆盖方式。
- 依赖和运行环境:支持的浏览器、React/Vue 版本、SSR 和样式注入策略。
- 发布契约:入口、类型声明、CSS 产物、语义化版本和弃用周期。
不要把业务接口、后端数据模型或某个页面的特殊流程直接塞进通用组件;应通过组合和插槽保留扩展空间。
2. API 设计优先于视觉细节
组件 API 应让状态来源清楚。以输入框为例,受控模式的 value 与 onChange 是唯一事实来源,非受控模式使用 defaultValue,两者不能在生命周期中无提示地互相切换。事件名称、键盘行为和 ref 语义应在文档中稳定下来。
复杂组件建议拆成“状态模型 + 视图部件”:例如弹窗由 open/onOpenChange 管理状态,标题、内容和操作区通过组合传入。这样既便于无头使用,也避免组件内部耦合业务文案。
3. 设计令牌与主题
不要在每个组件里散落颜色和间距常量。令牌可以先以 CSS 自定义属性表达:
:root {
--color-primary: #2563eb;
--color-surface: #ffffff;
--color-text: #111827;
--space-2: 8px;
--radius-sm: 4px;
}
[data-theme='dark'] {
--color-surface: #111827;
--color-text: #f9fafb;
}
组件只消费语义令牌,如 --color-surface,不直接依赖某个品牌色。令牌变更应有可视化回归和迁移说明。
4. 包结构与构建产物
中大型库可采用 monorepo,但包边界应按职责拆分,例如 core、tokens、icons、react 和 vue。每个包声明自己的依赖,跨包引用优先使用公开入口,避免深层路径耦合。
推荐同时提供现代 ESM 和项目需要的兼容格式,并生成 .d.ts:
{
"name": "@acme/ui",
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
},
"./styles.css": "./dist/styles.css"
},
"sideEffects": ["**/*.css"],
"peerDependencies": { "react": ">=18" }
}
exports 明确公开入口,peerDependencies 避免重复安装框架,sideEffects 要与真实副作用一致,否则可能错误删除样式或阻止 tree-shaking。发布前应检查包内没有源码地图中的敏感路径、测试夹具或本地配置。
5. 可访问性与跨框架行为
组件库不能把可访问性留给业务方:按钮、弹窗、菜单、表格和表单要覆盖语义元素、焦点管理、键盘导航、ARIA 状态和对比度。弹窗关闭后应把焦点还给触发元素;异步加载和错误状态要能被辅助技术感知。
如果同时支持 React 和 Vue,优先共享令牌、无头逻辑和测试用例,再分别适配渲染层。不要假设两个框架的生命周期、事件对象或插槽模型完全相同。
6. 测试与文档
- 单元测试验证状态转移、边界输入和事件顺序。
- 组件级交互测试验证键盘、焦点、表单校验和异步状态。
- 视觉回归测试锁定主题、尺寸和关键组合,而不是只截一张默认状态。
- SSR/水合测试检查服务端与客户端首屏标记一致。
- 文档示例应可运行,并展示受控、非受控、错误和禁用状态。
测试夹具与组件 API 一起维护;修复一个可复现缺陷时,优先增加能描述该行为的回归测试。
7. 版本与发布流程
使用语义化版本表达兼容性:新增可选能力通常是 minor,修复是 patch,删除或改变默认行为是 major。弃用 API 时先提供迁移提示和替代方案,至少跨一个发布周期再删除。变更日志应说明影响范围、迁移步骤和是否需要重新生成快照。
CI 至少执行类型检查、Lint、单元/交互测试、构建和包内容检查;发布采用不可变版本,避免同一版本号覆盖不同产物。组件库官网、示例和实际发布包应来自同一提交,减少“文档能用但包不可用”的偏差。
8. 常见反模式
- 用一个巨大的
UI包承载所有框架和业务依赖,导致安装和构建成本失控。 - 只测截图不测键盘、焦点和受控状态。
- 通过深层文件路径引用内部实现,后续重构无法保持兼容。
- 把破坏性变更伪装成 patch,迫使业务方在无迁移说明的情况下升级。