← 返回项目
Design System

qdma-ui · 自研组件库

Vue3 + ESM 按需引入 + Design Token + Storybook + 私有 npm,用组件契约收敛重复 UI 与包体失控,附七阶段、12 个坑与防回退机制。

Vue3RollupDesign TokenStorybook
8.17 → 5.29MB包体 -35.3%
3.2 → 2.14sWiFi 加载
61 → 89Lighthouse

qdma-ui · 自研组件库

Vue3 + ESM 按需引入 + Design Token + Storybook + 私有 npm,用组件契约收敛重复 UI 与包体失控。

30 秒电梯版

门店助手 H5 早期为赶进度引了三套 UI 库,同一业务出现 3 种按钮样式、3 套表单校验、2 套弹窗实现;加上分包粗放,H5 包体涨到 8.17MB,门店 WiFi 下加载 3.2 秒。我判断继续「换一个库」解决不了问题——问题是缺一层自己的业务组件契约。所以从 0 搭了 qdma-ui:Vue3 + Rollup 多产物、ESM 按需引入、统一 design token、10+ 核心业务组件、Storybook + 单测、私有 npm。全量替换三方库后,包体 8.17MB → 5.29MB(↓35.3%),依赖 ↓45.1%,WiFi 加载 3.2s → 2.14s,Lighthouse 61 → 89。

为什么要自研:先回答「这不是造轮子吗」

先说什么时候不该自研:只需要通用基础组件、团队 <5 人、没有明确业务组件诉求。

再说为什么必须自研

理由表现为什么现成库解决不了
三库并存契约不统一3 种按钮、2 套弹窗、校验各写各的换库只是换一家,多套在契约就永远不统一
体积失控8.17MB、WiFi 3.2s,大量组件用不上却打不进 tree-shaking第三方库为通用性牺牲体积,只有自己的库能精确裁剪
业务定制被卡地址级联、扫码上传、离线表单三方库改不动fork 三方库背上长期 rebase 成本

一句话:自研的不是「基础组件」,是「业务组件契约 + 体积控制权」。基础能力站在成熟库肩膀上,业务语义层必须自己握在手里。

七阶段

盘点 → 排优先级 → Rollup 基建 → Token 先行 → 组件开发 → 灰度替换 → 发布治理

  1. 盘点:按使用次数排序,常发现「引了 200 个组件实际只用 30 个」。
  2. 优先级:P0 表单/表格/弹窗(高频+强业务);P1 上传/级联/步骤条(业务特有);P2 按钮/标签/空态(便宜但统一视觉)。
  3. Rollup 基建:多产物(ESM/CJS/UMD)+ .d.ts + 独立 CSS。external: ['vue'] 是底线
  4. Design Token 先行(顺序不能反,先写组件再抽 token 等于重写)。
  5. 组件开发:受控/非受控双通道、$attrs 透传、插槽优先、语义化变体。
  6. 灰度替换:一次替换一类组件(按钮→弹窗→表单/表格),新旧并存可回滚,逐项记录体积。
  7. 发布治理:私有 npm + semantic versioning + 自动 CHANGELOG + CI(lint→test→build→size-check→publish)。

Design Token 三层

原始值(palette)→ 语义层(semantic,业务只认这层)→ 组件级(component)

业务只用语义层,换主题 = 覆盖语义层变量;组件内不写死任何颜色值(stylelint 卡住硬编码)。

按需引入与 tree-shaking(最经典坑)

「写了 ESM」不等于「能 tree-shake」。体积反弹根因:export * 全量导出,构建工具不敢裁。解法:

  1. "sideEffects": ["*.css"]
  2. 多入口(@qdma/ui/es/button 按路径引入)
  3. babel-plugin-import 兜底老构建链路
  4. externalpeerDependencies 成对(Vue 必须 external,否则双 Vue 实例响应式失效)
  5. CI 体积对比门禁

坑清单(12 条核心)

#根因
1打包进了 Vue,双实例external 没配全(带路径引用没匹配上)
2体积没降反升全量导出,tree-shaking 失效
3样式顺序错乱CSS 产物顺序不可控
4TS 没类型提示未产出 .d.ts
5按需引入配置复杂没用 ESM 多入口
6组件 API 一改下游全红破坏性变更未走 major
7Storybook 和产物不一致文档跑源码、业务用产物
8主题切换不彻底组件内硬编码色值
9覆盖率高仍有 bug只测函数没测交互路径
10构建产物残缺组件间循环依赖
11业务装不上版本冲突/peerDependencies 没声明
12体积反弹没依赖准入与体积门禁

长效防回退三件套

  1. 体积门禁:PR 对比产物体积,增长 <3% 通过、3~10% 警告、>10% fail
  2. 依赖准入:新增运行时依赖必须评审(有无现成能力/体积多大/能否按需引入)
  3. 性能预算:Lighthouse/体积阈值写进 CI,性能回归一票否决

量化结果(逐项归因)

  • 包体 8.17MB → 5.29MB(↓35.3%):三方库全量替换为按需 ESM + tree-shaking
  • 依赖包体积 ↓45.1%:三套 UI 库收敛为一套
  • WiFi 加载 3.2s → 2.14s(↓33.07%):包体下降 + 资源合并
  • Lighthouse 61 → 89:包体 + 主线程优化(TBT ↓47.2%)

讲效益分三层:体验层(加载/Lighthouse)、工程层(包体/依赖)、组织层(10+ 组件的统一契约,新项目复用)。长期价值最大的是组织层——体积是一次性的,契约是长期的。