文章目录

前端组件库设计学习笔记

适合目标:8 小时内建立前端组件库设计完整知识框架,覆盖组件库设计核心、目录结构、样式体系、构建产物、不同文件格式对应使用方式、工程化、发布流程与高频面试题。
学习重点:组件库不是“写几个组件”,而是“设计一套可复用、可维护、可发布、可扩展的 UI 能力系统”。
学习原则:先理解组件库解决什么问题,再学组件怎么写;先掌握设计原则,再看打包产物;先会讲架构,再讲 API 和构建细节。


目录

  1. 学习总览
  2. 组件库到底在解决什么
  3. 组件库设计核心
  4. 组件分层与目录结构
  5. 组件 API 设计
  6. 样式系统、主题与 Design Token
  7. 组件库构建与输出产物
  8. 不同文件格式对应的使用方式
  9. package.json 设计与发布字段
  10. Tree Shaking、按需加载与包体积优化
  11. 文档、测试、版本管理与发布
  12. 实战项目设计建议
  13. 高频面试题
  14. 更好记的学习方法
  15. 8 小时学习节奏建议
  16. 一页速记总结
  17. 背诵口诀

1. 学习总览

1.1 什么是前端组件库设计

很多人对组件库的第一印象是:

把 Button、Input、Modal 这些组件封装起来。

这只是最表层。

更完整地说,组件库设计学的是:

如何把零散的 UI 和交互能力,沉淀成一套稳定、统一、可复用、可发布、可扩展的前端基础设施。

所以组件库设计不只是写组件,而是要同时考虑:

  1. 组件 API 怎么设计
  2. 样式如何统一
  3. 主题如何切换
  4. 构建产物如何输出
  5. 不同项目如何接入
  6. TypeScript 类型怎么暴露
  7. 文档、测试、版本和发布怎么做

1.2 为什么组件库设计值得单独学

因为它是前端工程能力和 UI 设计能力的结合点。

一个成熟组件库,通常会体现:

  1. 代码复用能力
  2. API 抽象能力
  3. 工程化能力
  4. 视觉一致性能力
  5. 维护与演进能力

1.3 学这份笔记要抓哪几条主线

主线 1:组件库解决什么问题

  • 为什么要做统一组件
  • 为什么要做 Token、主题和规范

主线 2:组件库怎么设计

  • 组件怎么分层
  • API 怎么抽象
  • 样式怎么组织

主线 3:组件库怎么交付给别人用

  • 输出哪些文件
  • ESM / CJS / UMD / d.ts / CSS 分别给谁用
  • package.json 怎么配

主线 4:组件库怎么长期维护

  • 文档
  • 测试
  • 版本
  • 发布

1.4 核心记忆主线

把组件库设计记成一句话:

组件库 = 统一 UI 规则 + 稳定组件 API + 可交付构建产物 + 可持续维护机制。

再压缩成四个词:

抽象、统一、交付、演进


2. 组件库到底在解决什么

2.1 如果没有组件库,会出现什么问题

团队没有组件库时,常见问题有:

  1. 每个页面都在重复写按钮、弹窗、表单
  2. 同样的按钮在不同页面颜色、间距、行为不一致
  3. 不同人写出的交互细节不统一
  4. 修改设计规范时需要全项目手动改
  5. 很难沉淀 UI 规范和业务经验

2.2 组件库的核心价值

组件库的核心价值可以分成四类:

价值 说明
复用 减少重复开发
统一 统一视觉和交互规范
提效 提高开发效率和协作效率
沉淀 把经验沉淀为稳定基础设施

2.3 组件库不只是“UI 仓库”

很多人把组件库理解成“放组件代码的地方”,这不够完整。

一个成熟组件库往往包含:

  1. 基础组件
  2. 样式系统
  3. 主题机制
  4. 图标系统
  5. 类型定义
  6. 文档站点
  7. 测试和发布工具链

2.4 组件库和业务组件的区别

基础组件库

适合:

  1. Button
  2. Input
  3. Select
  4. Modal
  5. Table

特点:

  1. 通用性高
  2. 业务耦合低
  3. 适合多个项目复用

业务组件库

适合:

  1. 商品选择器
  2. 权限树
  3. 课程卡片
  4. 用户面板

特点:

  1. 更贴近业务
  2. 复用范围更偏业务域
  3. 依赖业务模型更多

一句话区分:

基础组件库解决通用 UI,业务组件库沉淀业务场景。

2.5 面试里怎么概括组件库

可以答:

组件库本质上是把 UI、交互、样式规范和工程能力沉淀成可复用基础设施,目标是提升开发效率、统一产品体验并降低长期维护成本。


3. 组件库设计核心

这一部分最重要。真正能区分“会写组件”和“会设计组件库”的,就是这里。

3.1 组件库设计的核心目标

设计组件库时,最核心的目标通常是:

  1. 易用
  2. 一致
  3. 可扩展
  4. 可维护
  5. 可发布

3.2 一个好组件库最重要的五个特征

特征 1:API 稳定

组件的 props、事件、插槽、暴露方法尽量清晰稳定。

特征 2:样式一致

颜色、字号、圆角、间距、动效有统一规范。

特征 3:组合灵活

既能满足常见场景,也不至于把组件写死。

特征 4:工程可交付

能输出被项目真正消费的产物,而不是只在本地 demo 能跑。

特征 5:可持续演进

支持文档、测试、版本升级和兼容策略。

3.3 设计组件库时,最容易犯的几个错误

  1. 过早追求“大而全”
  2. API 命名不统一
  3. 组件耦合业务过深
  4. 样式无 Token 体系
  5. 打包产物只考虑一种场景
  6. 没有类型和文档

3.4 组件库设计的思维顺序

推荐按这个顺序思考:

  1. 这类组件解决什么问题
  2. 最小可用能力是什么
  3. 哪些能力必须内置
  4. 哪些能力应该交给外部定制
  5. 这个组件如何和其他组件协作
  6. 最终产物要怎么提供给使用方

3.5 设计组件时,什么时候做“能力下沉”

比如多个组件都有:

  1. loading 状态
  2. disabled 状态
  3. size 体系
  4. 主题色体系

这时就应该考虑抽象:

  1. 基础样式变量
  2. 通用 hooks
  3. 通用工具函数
  4. 基础交互层

3.6 组件库不是所有东西都要做成组件

组件库里除了组件,还会有:

  1. hooks
  2. 工具函数
  3. 指令
  4. 类型工具
  5. 主题 Token

所以它更像:

一套 UI 基础能力平台

3.7 一句话压缩组件库设计核心

组件库设计的关键不是组件数量,而是抽象边界、API 稳定性和交付方式。


4. 组件分层与目录结构

4.1 为什么组件库需要分层

因为如果不分层,代码很快会变得:

  1. 相互依赖混乱
  2. 公共逻辑四处复制
  3. 样式和逻辑耦合严重
  4. 打包边界不清晰

4.2 一个常见组件库分层

你可以先记住这四层:

  1. 基础能力层
  2. 基础组件层
  3. 复合组件层
  4. 入口与导出层

4.3 基础能力层

一般包含:

  1. hooks
  2. utils
  3. constants
  4. types
  5. token

例如:

  1. useControlled
  2. useNamespace
  3. isNumber
  4. ThemeToken

4.4 基础组件层

常见有:

  1. Button
  2. Input
  3. Icon
  4. Tag
  5. Checkbox

这些组件通常:

  1. 通用性强
  2. 依赖少
  3. 是其他复合组件的积木

4.5 复合组件层

例如:

  1. DatePicker
  2. Table
  3. Upload
  4. Form
  5. Cascader

这些组件通常:

  1. 内部组合多个基础组件
  2. 逻辑更复杂
  3. API 更谨慎

4.6 入口与导出层

负责:

  1. 统一导出组件
  2. 统一导出 hooks 和类型
  3. 定义组件库对外 API 面

4.7 一个推荐目录结构

packages/ui/
  src/
    components/
      button/
        index.ts
        button.tsx
        style.css
        types.ts
      input/
      modal/
    hooks/
    utils/
    styles/
      index.css
      tokens.css
      reset.css
    types/
    index.ts
  dist/

4.8 Monorepo 下的组件库目录

如果组件库较大,常见会拆成:

packages/
  components/
  icons/
  themes/
  utils/
  docs/

这样做的好处:

  1. 职责更清晰
  2. 更适合多人协作
  3. 更利于独立版本或按包发布

4.9 一句话压缩分层

基础能力做下沉,基础组件做复用,复合组件做组合,入口层做统一导出。


5. 组件 API 设计

API 设计是组件库最容易“看起来简单、其实最难”的部分。

5.1 组件 API 设计要解决什么

本质上是在回答:

使用方要怎么最自然地使用这个组件。

5.2 API 设计的几个核心原则

  1. 命名一致
  2. 能力最小但够用
  3. 默认值合理
  4. 扩展方式清晰
  5. 控制与非控制模式明确

5.3 命名为什么很重要

如果一个组件库里同时出现:

  1. size
  2. btnSize
  3. type
  4. variant

但没有统一语义,使用者会很痛苦。

所以推荐统一:

  1. 外观:variant
  2. 尺寸:size
  3. 状态:disabledloading
  4. 值:value
  5. 事件:onChange

5.4 默认值设计为什么关键

一个好组件应该:

开箱即用

也就是说,使用者尽量只传最少参数就能得到合理结果。

5.5 控制模式与非控制模式

这是组件库面试高频点。

非受控

组件内部自己管理状态。

受控

状态完全由外部传入和控制。

例如表单组件常见设计:

<Input defaultValue="hello" />
<Input value={value} onChange={setValue} />

5.6 什么时候提供插槽或 children

如果组件内部布局需要留给使用方自由组合,就应该提供插槽能力。

例如:

  1. Card header
  2. Modal footer
  3. Dropdown content

5.7 什么时候提供 render props

适合:

  1. 高度定制渲染
  2. 复杂内部状态对外暴露
  3. 虚拟列表、表格单元格等场景

5.8 什么时候暴露实例方法

例如:

  1. focus
  2. scrollTo
  3. open
  4. close

只有当组件存在明显 imperative 场景时再暴露。

5.9 API 设计里最常见的错误

  1. props 太多
  2. 一个 prop 兼顾太多语义
  3. 受控和非受控混用不清
  4. 事件命名不统一
  5. 为了灵活把所有东西都交给使用方

5.10 一句话压缩 API 设计

组件 API 要让常见场景简单,让复杂场景可扩展,但不能失控。


6. 样式系统、主题与 Design Token

6.1 为什么组件库一定会谈样式系统

因为组件库不只是逻辑复用,更重要的是:

视觉和交互规则统一。

6.2 什么是 Design Token

Design Token 可以理解成:

把颜色、字号、间距、圆角、阴影等设计值抽象成统一变量。

例如:

:root {
  --ui-color-primary: #1677ff;
  --ui-radius-sm: 4px;
  --ui-font-size-md: 14px;
}

6.3 为什么 Token 很重要

因为它能把:

  1. 视觉规范
  2. 组件实现
  3. 主题切换

连接起来。

6.4 主题系统常见做法

  1. CSS Variables
  2. Less / Sass Variables
  3. JS Theme Object
  4. Design Token 编译产物

6.5 为什么现在常说 CSS Variables

因为它更适合:

  1. 运行时切换主题
  2. 动态皮肤
  3. 暗黑模式
  4. 浏览器原生支持好

6.6 组件库样式常见策略

方式 特点 适合场景
全局 CSS 简单直接 小型组件库
CSS Modules 避免冲突 中小型项目
CSS-in-JS 动态能力强 特定技术栈
Less / Sass 变量和预处理成熟 传统组件库
CSS Variables + 编译样式 平衡灵活与性能 现代组件库

6.7 为什么要做命名空间

比如:

.ui-button {}
.ui-input {}

这样做的作用:

  1. 避免样式冲突
  2. 更利于调试
  3. 更适合对外发布

6.8 一句话压缩样式系统

组件库样式的关键不是“能写出来”,而是“能统一、能切主题、能长期演进”。


7. 组件库构建与输出产物

这是你特别点名的重点。组件库不是只把源码发出去,而是要输出适合不同使用场景的构建产物。

7.1 为什么组件库要构建

因为源码通常包含:

  1. TypeScript
  2. JSX / TSX
  3. 源样式文件
  4. 私有目录结构

使用者真正需要的是:

  1. 可直接导入的 JS
  2. 对应的类型文件
  3. 可加载的样式文件
  4. 明确的导出入口

7.2 组件库常见输出内容

一般会输出:

  1. ESM
  2. CJS
  3. UMD 或浏览器 bundle
  4. d.ts
  5. CSS
  6. source map

7.3 一个常见的 dist 结构

dist/
  es/
    index.js
    button/index.js
  lib/
    index.js
    button/index.js
  types/
    index.d.ts
    button/index.d.ts
  style.css
  index.umd.js

7.4 为什么同一个组件库要输出多种格式

因为消费方环境不一样:

  1. 有的项目用现代 bundler
  2. 有的项目仍依赖 CommonJS
  3. 有的场景直接浏览器 <script> 引入
  4. TypeScript 项目还要类型

7.5 构建工具常见选择

常见有:

  1. Rollup
  2. Vite library mode
  3. tsup
  4. webpack

学习阶段推荐先理解:

Rollup / Vite / tsup

因为它们更常用于组件库场景。

7.6 为什么 Rollup 常用于组件库

因为它对库构建更友好:

  1. 输出格式丰富
  2. Tree Shaking 友好
  3. 多入口支持清晰
  4. 产物更适合作为库发布

7.7 样式文件构建时常见问题

要考虑:

  1. CSS 是合并成一个文件,还是按组件拆分
  2. 是否支持按需引入样式
  3. Less / Sass 是否也要对外暴露源码

7.8 一句话压缩构建产物

组件库构建的目标,是把源码转成不同消费场景都能稳定接入的交付物。


8. 不同文件格式对应的使用方式

这一部分非常重要。很多人知道 ESMCJS 这些词,但不知道“为什么要发它”“谁在用它”“怎么接入它”。

8.1 ESM 是什么

ESM 即 ECMAScript Modules

常见写法:

import { Button } from "@demo/ui";

8.2 ESM 适合什么场景

适合:

  1. Vite 项目
  2. Rollup 项目
  3. 现代 Webpack 项目
  4. 现代前端库消费场景

8.3 为什么组件库通常要输出 ESM

因为它更适合现代构建工具做:

  1. Tree Shaking
  2. 按需打包
  3. 更细粒度依赖分析

8.4 ESM 的典型使用方式

import { Button } from "@demo/ui";
import "@demo/ui/style.css";

如果支持按组件引入:

import Button from "@demo/ui/es/button";
import "@demo/ui/es/button/style.css";

8.5 CJS 是什么

CJS 即 CommonJS

常见写法:

const { Button } = require("@demo/ui");

8.6 CJS 适合什么场景

适合:

  1. 老 Node 环境
  2. 某些旧构建工具
  3. 一些历史 SSR 场景

8.7 为什么很多组件库仍会输出 CJS

因为现实项目里还存在:

  1. 历史工程兼容需求
  2. 某些工具链仍依赖 require
  3. 部分生态仍使用 CommonJS

8.8 UMD 是什么

UMD 可以理解成:

浏览器和多种模块系统兼容的老牌通用格式。

常见用途是:

  1. CDN 脚本直引
  2. Demo 页面
  3. 不经过 bundler 的场景

8.9 UMD 的典型使用方式

<link rel="stylesheet" href="https://cdn.example.com/ui/style.css" />
<script src="https://cdn.example.com/ui/index.umd.js"></script>
<script>
  const Button = DemoUI.Button;
</script>

8.10 d.ts 是什么

d.ts 是 TypeScript 类型声明文件。

它的作用是:

  1. 提示组件 props
  2. 提示函数参数和返回值
  3. 提升 IDE 自动补全体验

8.11 d.ts 对使用方有什么价值

例如:

import { Button } from "@demo/ui";

这时 IDE 能知道:

  1. Button 有哪些 props
  2. 每个 prop 的类型是什么
  3. 事件签名是什么

8.12 CSS 文件输出是干什么的

CSS 文件是给使用方直接加载样式的。

典型方式:

import "@demo/ui/style.css";

8.13 为什么组件库有时会同时输出 style.csses/button/style.css

这是为了兼顾两类使用方式:

  1. 全量引入样式
  2. 按需引入单个组件样式

8.14 Less / Sass 源文件要不要发布

要看你的组件库定位。

如果你希望使用方深度定制主题,可能会发布:

  1. theme.less
  2. variables.scss

这样使用方可以在编译阶段覆盖变量。

8.15 Source Map 有什么用

Source Map 主要用于:

  1. 调试源码
  2. 定位报错
  3. 帮助库开发者和接入方排查问题

8.16 不同产物格式和使用方式总表

产物格式 作用 常见使用方式 适合场景
ESM 现代模块产物 import { Button } from "@demo/ui" 现代前端项目
CJS 兼容旧模块系统 const ui = require("@demo/ui") 历史项目、旧 Node 环境
UMD 浏览器全局脚本 <script src="..."> CDN 直引、Demo
d.ts 类型声明 自动被 TS 识别 TypeScript 项目
CSS 样式产物 import "@demo/ui/style.css" 所有前端项目
Less/Scss 可编译主题变量 @use / @import 深度定制场景

8.17 一句话压缩不同文件格式

ESM 给现代工程,CJS 给兼容场景,UMD 给浏览器直引,d.ts 给类型系统,CSS 给样式加载。


9. package.json 设计与发布字段

组件库能不能被别人正确使用,很大程度取决于 package.json 怎么写。

9.1 为什么 package.json 对组件库很关键

因为它在告诉使用方和构建工具:

  1. 入口文件在哪
  2. 模块格式是什么
  3. 类型文件在哪
  4. 样式入口在哪
  5. 哪些文件要发布

9.2 组件库最常见的几个字段

字段 作用
main CommonJS 入口
module ESM 入口
types 类型声明入口
exports 精细控制导出
files 控制发布哪些文件
sideEffects 帮助 Tree Shaking
peerDependencies 声明宿主依赖

9.3 main 是什么

通常指向 CommonJS 入口:

{
  "main": "dist/lib/index.js"
}

9.4 module 是什么

通常指向 ESM 入口:

{
  "module": "dist/es/index.js"
}

9.5 types 是什么

指定类型入口:

{
  "types": "dist/types/index.d.ts"
}

9.6 exports 为什么越来越重要

因为它可以更精细地控制:

  1. import 走哪个文件
  2. require 走哪个文件
  3. 子路径导出哪些可用
  4. 是否对外隐藏内部文件结构

9.7 一个推荐的 exports 示例

{
  "exports": {
    ".": {
      "types": "./dist/types/index.d.ts",
      "import": "./dist/es/index.js",
      "require": "./dist/lib/index.js"
    },
    "./style.css": "./dist/style.css",
    "./button": {
      "types": "./dist/types/button/index.d.ts",
      "import": "./dist/es/button/index.js",
      "require": "./dist/lib/button/index.js"
    }
  }
}

9.8 files 为什么重要

它决定发布到 npm 时,哪些内容会被带上。

例如:

{
  "files": ["dist"]
}

这样可以避免把源码、测试、临时文件都发出去。

9.9 peerDependencies 为什么在组件库里很常见

例如 React 组件库通常不会自己打包 React,而是声明:

{
  "peerDependencies": {
    "react": ">=18",
    "react-dom": ">=18"
  }
}

原因是:

  1. 避免宿主项目和组件库各自带一份 React
  2. 避免运行时实例不一致

9.10 sideEffects 为什么很关键

它会影响 Tree Shaking。

例如:

{
  "sideEffects": [
    "*.css"
  ]
}

这表示:

  1. JS 模块可以尝试摇树优化
  2. CSS 不能被误删

9.11 一个更完整的组件库 package.json 示例

{
  "name": "@demo/ui",
  "version": "1.0.0",
  "main": "dist/lib/index.js",
  "module": "dist/es/index.js",
  "types": "dist/types/index.d.ts",
  "style": "dist/style.css",
  "files": ["dist"],
  "sideEffects": ["*.css"],
  "peerDependencies": {
    "react": ">=18",
    "react-dom": ">=18"
  },
  "exports": {
    ".": {
      "types": "./dist/types/index.d.ts",
      "import": "./dist/es/index.js",
      "require": "./dist/lib/index.js"
    },
    "./style.css": "./dist/style.css"
  }
}

9.12 一句话压缩 package.json

package.json 是组件库的交付说明书,决定别人如何找到并正确使用你的产物。


10. Tree Shaking、按需加载与包体积优化

10.1 为什么组件库要特别关注包体积

因为组件库会被很多项目依赖。

如果组件库太重,会影响:

  1. 业务项目打包体积
  2. 首屏性能
  3. 安装和构建速度

10.2 Tree Shaking 是什么

Tree Shaking 是构建阶段移除未使用代码的能力。

组件库想让 Tree Shaking 更好生效,通常要做到:

  1. 输出 ESM
  2. 避免无必要副作用
  3. 合理设置 sideEffects

10.3 什么是按需加载

按需加载可以理解成:

只引入真正用到的组件和样式,而不是整个组件库。

例如:

import Button from "@demo/ui/es/button";
import "@demo/ui/es/button/style.css";

10.4 全量引入和按需引入的区别

全量引入

import { Button, Input } from "@demo/ui";
import "@demo/ui/style.css";

适合:

  1. 小型项目
  2. 快速接入
  3. 组件使用较多

按需引入

import Button from "@demo/ui/es/button";
import "@demo/ui/es/button/style.css";

适合:

  1. 更关注包体积
  2. 大型项目
  3. 组件使用相对分散

10.5 为什么样式也要支持按需

因为如果 JS 按需了,但样式还是全量加载,优化效果会打折。

10.6 包体积优化常见手段

  1. ESM 输出
  2. 按组件拆包
  3. 样式按需输出
  4. 图标单独拆分
  5. 避免把宿主依赖打进库里
  6. 抽离共享工具

10.7 一句话压缩优化

组件库优化的核心是:让使用方只拿到真正需要的代码和样式。


11. 文档、测试、版本管理与发布

11.1 为什么组件库必须重视文档

因为组件库的用户就是“开发者”。

如果没有文档,再好的组件也很难被正确使用。

11.2 组件文档至少要包含什么

  1. 基本介绍
  2. 使用示例
  3. props 说明
  4. 事件说明
  5. 插槽 / children 说明
  6. 主题定制说明

11.3 组件库测试重点测什么

常见测试:

  1. 渲染测试
  2. 交互测试
  3. 快照测试
  4. 样式类名测试
  5. 无障碍测试

11.4 视觉回归为什么重要

因为组件库改动经常影响:

  1. 样式
  2. 布局
  3. 交互状态

所以很多团队会加入视觉回归测试。

11.5 版本管理为什么关键

因为组件库是被多个项目消费的。

一旦升级不谨慎,就会影响很多业务。

11.6 什么是语义化版本

通常是:

major.minor.patch

含义:

  1. major:破坏性变更
  2. minor:向后兼容的新功能
  3. patch:向后兼容的问题修复

11.7 发布流程一般包含什么

  1. lint
  2. test
  3. build
  4. changelog
  5. version bump
  6. publish

11.8 一句话压缩文档和发布

组件库不是写完代码就结束,而是要让别人看得懂、用得稳、升得动。


12. 实战项目设计建议

12.1 一个适合起步的组件库范围

建议先做最基础的一组:

  1. Button
  2. Input
  3. Icon
  4. Modal
  5. Message
  6. Tabs

12.2 第一阶段应该先做什么

先做:

  1. 命名规范
  2. Token 系统
  3. 基础目录结构
  4. 构建产物
  5. 文档基础设施

不要一开始就先冲复杂组件。

12.3 一个真实项目的设计主线

推荐按这个顺序:

  1. 定义设计规范
  2. 定义 Token
  3. 设计 Button / Input 等基础组件
  4. 设计库入口和构建方案
  5. 输出 ESM / CJS / d.ts / CSS
  6. 写文档和示例
  7. 发布 npm 包

12.4 如果是 React 组件库,要重点注意什么

  1. peerDependencies 中声明 React
  2. hooks 抽象
  3. ref 暴露
  4. controlled/uncontrolled 模式

12.5 如果是 Vue 组件库,要重点注意什么

  1. 插槽设计
  2. install 机制
  3. 全局注册与按需注册
  4. 组合式 API 与类型暴露

12.6 一句话压缩实战建议

先做规范和构建底座,再做组件;先做基础组件,再做复杂组件。


13. 高频面试题

13.1 什么是前端组件库

可以答:

组件库是把通用 UI、交互规则、样式规范和工程能力沉淀成可复用基础设施的一套系统。

13.2 为什么要做组件库

可以答:

主要是为了提升复用效率、统一视觉和交互规范、降低重复开发成本,并把团队经验沉淀下来。

13.3 组件库设计最核心的点是什么

可以答:

核心在于抽象边界、API 稳定性、样式和主题体系、构建产物设计以及长期维护能力。

13.4 组件库和业务组件有什么区别

可以答:

基础组件库偏通用、低耦合,适合多项目复用;业务组件库更贴近具体业务场景,复用范围更偏业务域。

13.5 为什么组件库通常要输出 ESM 和 CJS

可以答:

因为不同消费环境不同,现代 bundler 更适合用 ESM 做 Tree Shaking,历史项目或旧 Node 场景仍可能依赖 CommonJS。

13.6 ESM、CJS、UMD 分别适合什么场景

可以答:

  1. ESM:现代工程化项目
  2. CJS:历史兼容场景
  3. UMD:浏览器 <script> 直引和 Demo 场景

13.7 d.ts 文件是做什么的

可以答:

它是 TypeScript 类型声明文件,用于给使用方提供 props、事件和 API 的类型提示。

13.8 mainmoduletypes 分别是什么

可以答:

  1. main:CommonJS 入口
  2. module:ESM 入口
  3. types:类型声明入口

13.9 exports 字段有什么用

可以答:

它用于更精细地控制包对外暴露的入口,可以分别定义 import、require、types 等不同条件下的导出路径。

13.10 为什么 peerDependencies 对组件库很重要

可以答:

因为组件库往往依赖宿主框架,比如 React/Vue,但又不希望把框架自身打进包里,否则容易产生多份实例和运行时问题。

13.11 为什么要设置 sideEffects

可以答:

它用于帮助构建工具做 Tree Shaking,并避免像 CSS 这类有副作用的文件被错误删除。

13.12 按需加载怎么实现

可以答:

通常是组件库按组件拆分产物,并暴露子路径入口,同时样式也支持按组件引入,这样业务项目只会加载实际使用的组件和样式。

13.13 组件库怎么做主题定制

可以答:

一般通过 Design Token、CSS Variables、预处理变量或 JS Theme Object 来实现统一主题和动态皮肤切换。

13.14 如果让你设计一个组件库,你会怎么做

推荐答法:

  1. 先梳理设计规范和 Token
  2. 设计基础目录和分层
  3. 先做基础组件
  4. 设计统一 API 风格
  5. 输出 ESM / CJS / d.ts / CSS
  6. 补文档、测试和发布流程

14. 更好记的学习方法

14.1 用一句话记住组件库

组件库不是几个组件,而是一套可复用的 UI 基础设施。

14.2 用“三问法”来记

每学一个点都问自己:

  1. 它解决什么问题
  2. 它对使用方有什么价值
  3. 它最终怎么交付出去

14.3 用“设计到交付”链路记忆

把组件库压成这条链:

设计规范 -> Token -> 组件 API -> 样式系统 -> 构建产物 -> package.json -> 发布

14.4 用对比法记

对比 1:基础组件库 vs 业务组件库

  • 基础组件库:通用
  • 业务组件库:业务场景化

对比 2:ESM vs CJS vs UMD

  • ESM:现代工程
  • CJS:兼容旧系统
  • UMD:浏览器直引

对比 3:全量引入 vs 按需引入

  • 全量引入:方便
  • 按需引入:更省包体积

14.5 用口诀记

  1. 先统一规范,再统一组件
  2. Token 管设计,API 管使用,构建管交付
  3. ESM 给现代工程,CJS 给兼容场景,UMD 给浏览器直引
  4. types 管提示,CSS 管样式,exports 管入口

14.6 最有效的记忆方式

你最好能做到:

  1. 画出组件库分层结构
  2. 手写一个 package.json 导出配置
  3. 说清 ESM/CJS/UMD 的使用区别
  4. 讲一个从 Button 到发布 npm 包的完整链路

15. 8 小时学习节奏建议

第 1 小时:建立总框架

目标:

  1. 理解组件库到底在解决什么
  2. 区分基础组件库和业务组件库
  3. 记住“抽象、统一、交付、演进”

第 2-3 小时:集中突破组件设计

重点:

  1. 分层设计
  2. API 设计
  3. 控制与非控制模式
  4. 样式命名和主题体系

输出目标:

能说清一个 Button 组件为什么这样设计

第 4-5 小时:集中突破构建产物和输出格式

重点:

  1. ESM
  2. CJS
  3. UMD
  4. d.ts
  5. CSS
  6. exports / main / module / types

输出目标:

能讲清不同产物格式对应的使用方式

第 6 小时:包体积与按需加载

重点:

  1. Tree Shaking
  2. sideEffects
  3. 按组件拆包
  4. 样式按需引入

第 7 小时:文档、测试、版本和发布

重点:

  1. 文档结构
  2. 测试策略
  3. 语义化版本
  4. 发布流程

第 8 小时:冲刺复盘

做三件事:

  1. 默写一页总结
  2. 回答面试题
  3. 用 5 分钟讲一遍“如何设计一个组件库”

16. 一页速记总结

16.1 组件库核心

组件库 = 统一 UI 规范 + 可复用组件 + 可交付产物 + 可持续维护机制

16.2 设计核心

  • 抽象边界
  • API 稳定
  • 样式统一
  • 主题可扩展

16.3 常见产物

  • ESM
  • CJS
  • UMD
  • d.ts
  • CSS

16.4 使用方式

  • ESM:import
  • CJS:require
  • UMD:script
  • d.ts:TS 自动识别
  • CSS:样式直接导入

16.5 package.json 核心字段

  • main
  • module
  • types
  • exports
  • files
  • sideEffects
  • peerDependencies

16.6 优化核心

  • 输出 ESM
  • 正确配置 sideEffects
  • 支持按需引入
  • 样式按需拆分

16.7 最重要的一句话

组件库真正难的不是“写组件”,而是“把组件做成稳定、统一、可交付、可演进的产品”。


17. 背诵口诀

17.1 总口诀

先做规范,再做组件;先做 API,再做构建;先能使用,再谈扩展。

17.2 产物口诀

ESM 给现代,CJS 给兼容,UMD 给浏览器,types 给提示,CSS 给样式。

17.3 设计口诀

Token 定视觉,API 定交互,exports 定入口。

17.4 工程口诀

组件要分层,样式要统一,打包要多格式,发布要可维护。

17.5 面试口诀

回答组件库问题时,尽量按这个顺序说:

  1. 它解决什么问题
  2. 组件怎么分层和抽象
  3. API 和主题怎么设计
  4. 产物怎么输出
  5. 如何发布和维护

只要你按这个顺序说,答案通常会比较完整。


附:你可以怎么用这份笔记

第一次学习

重点看:

  1. 组件库到底在解决什么
  2. 组件库设计核心
  3. 组件分层与 API 设计

第二次复习

重点看:

  1. 样式系统与 Token
  2. 构建与输出产物
  3. package.json 设计

第三次冲刺

只看:

  1. 不同文件格式对应的使用方式
  2. 一页速记总结
  3. 高频面试题

如果你能把这三部分不看笔记讲出来,说明你已经真正掌握了组件库设计这块内容。