包与依赖关系
XiHan.UI 是一个 pnpm workspace。packages/*/* 是对外发布的库包(按角色分 adapters / design / features / engine 四组),tooling/* 是内部工具(不发布)。
全部库包
| 包 | 依赖 | peer 依赖 | 层 |
|---|---|---|---|
@xihan-ui/core | motion | — | 1 |
@xihan-ui/tokens | — | — | 1 |
@xihan-ui/icons | — | — | 1 |
@xihan-ui/motion | — | — | 1 |
@xihan-ui/pointer | — | — | 1 |
@xihan-ui/viz | — | — | 1 |
@xihan-ui/position | core | — | 2 |
@xihan-ui/code-highlight | core | — | 2 |
@xihan-ui/chat-stream | core | — | 2 |
@xihan-ui/markdown | — | — | 2 |
@xihan-ui/sound | core | — | 2 |
@xihan-ui/animations | core motion | — | 2 |
@xihan-ui/headless | core motion pointer viz | — | 3 |
@xihan-ui/styles | tokens(只取其 CSS 产物) | — | 3 |
@xihan-ui/backgrounds | core motion | — | 3 |
@xihan-ui/vue | core motion pointer viz headless position | vue、backgrounds(可选)、sound(可选)、code-highlight(可选) | 4 |
@xihan-ui/web-components | core motion pointer viz headless position | backgrounds(可选)、code-highlight(可选) | 4 |
发布走 changesets,所有库包同属一个 fixed 版本组,一起升到同一个版本号。
依赖图
箭头方向 = 依赖方向,只画实际声明的依赖。同层之间只有 core → motion 一条横向依赖。
层 4 ┌─────────────┐ ┌──────────────────┐
│ vue │ │ web-components │ peer: backgrounds · code-highlight(可选);vue 另有 peer: sound(可选)、vue
└──────┬──────┘ └────────┬─────────┘
│ core · motion · pointer · viz · headless · position
└───────────┬───────────┘
▼
层 3 ┌──────────────┐ ┌───────────────────┐ ┌────────────────┐
│ headless │ │ backgrounds │ │ styles(纯CSS)│
└──────┬───────┘ └─────────┬─────────┘ └───────┬────────┘
core·motion·pointer·viz core·motion tokens 的 CSS 产物
│ │
▼ ▼
层 2 ┌──────────┐ ┌────────────────┐ ┌─────────────┐ ┌───────┐ ┌────────────┐ ┌──────────┐
│ position │ │ code-highlight │ │ chat-stream │ │ sound │ │ animations │ │ markdown │
└────┬─────┘ └───────┬────────┘ └──────┬──────┘ └───┬───┘ └─────┬──────┘ └──────────┘
└───────────────┴─────────────────┴───────────┴───────────┘ 无依赖
▼
层 1 ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────┐ ┌─────────┐ ┌─────┐
│ core │─►│ motion │ │ tokens │ │ icons │ │ pointer │ │ viz │
└──────────┘ └──────────┘ └──────────┘ └───────┘ └─────────┘ └─────┘
零运行时依赖 无依赖 无依赖 无依赖 无依赖三个包完全独立,可以单独使用:
@xihan-ui/tokens:只需要设计令牌与主题运行时,不需要组件;@xihan-ui/markdown:只需要流式 Markdown 渲染内核;@xihan-ui/styles:纯 CSS,它对tokens的依赖只是为了@import令牌产物,不引入任何 JS。
依赖规则
分层拓扑写在 tooling/eslint-config/src/layers.json 中,由 dependency-cruiser 在 pnpm boundaries 时强制。层级越低越基础,只能依赖 canDependOn 列出的包。
除分层外还有四条规则:
| 规则 | 内容 |
|---|---|
no-circular | 禁止循环依赖 |
no-unresolvable | 无法解析的 import:最常见的成因是引用了邻层却未在 package.json 中声明依赖 |
styles-no-js-deps | styles 是纯 CSS,不得依赖任何 JS 包 |
no-external-in-packages | 库包的运行时代码不得引入第三方 |
第三方运行时依赖
没有。登记在案的例外只有适配器的宿主框架:@xihan-ui/vue 的 vue,@xihan-ui/react 的 react 与 react-dom。
以下能力均为自研,不引入第三方:
| 能力 | 包 | 常见的第三方选择 |
|---|---|---|
| 日期运算、时区换算与按地区的周 | core(@xihan-ui/core/date) | date-fns / Day.js / @internationalized/date |
| 浮层定位 | position | Floating UI |
| 代码着色 | code-highlight | Shiki / Prism |
| Web Components 响应式基类 | web-components | Lit |
| Markdown 渲染 | markdown | markdown-it / marked |
| 状态机 | core | XState |
新增第三方运行时依赖必须逐条登记进白名单并写明理由与移除条件,由 check-runtime-deps 门禁保证。
开发期第三方依赖另行处理
@lit/reactive-element 与 commonmark-spec 出现在 workspace catalog 中,但只供测试比对:前者用于差分校验自研响应式基类,后者用于读取 CommonMark 官方用例。两者都不进入任何包的运行时依赖。
版本约定
- 内部运行时依赖一律
workspace:^(发布时展开为当前锁步版本的^区间),内部开发期依赖用workspace:*; - 第三方版本只从 workspace catalog 取,包内写
catalog:,不得内联版本号(check-exact-pins门禁); - 升级只改
pnpm-workspace.yaml的 catalog 一处。
产物契约
| 项 | 值 |
|---|---|
| 模块格式 | ESM only,不提供 CJS |
| Node | >= 18 |
| 类型 | 每个入口一份 .d.ts |
| 副作用 | 全部 sideEffects: false,styles 与 tokens/tokens.css 除外 |
pnpm gate:publish 逐包运行 publint 与 attw,按 ESM-only 的支持面校验 exports 条件与类型解析(node16-from-ESM 与 bundler 两列)。
子路径导出
主入口之外另有子路径的包:
| 包 | 子路径 |
|---|---|
@xihan-ui/core | ./metadata ./skin-check ./vite ./vanilla ./presence |
@xihan-ui/tokens | ./runtime ./tokens.css ./tokens.json |
@xihan-ui/icons | ./codegen |
@xihan-ui/vue | ./backgrounds ./behavior ./sound |
@xihan-ui/web-components | ./define ./backgrounds ./custom-elements.json |
@xihan-ui/styles | 每份皮肤一条 CSS,共 148 条(136 份组件皮肤 + 12 份共享层),另有 ./index.css(主入口,生成的扁平有层文件,家族只内联一次)与 ./index.unlayered.css 两个整包入口 |
其余十一个包(headless / motion / pointer / viz / position / code-highlight / animations / backgrounds / chat-stream / markdown / sound)只有主入口。
组件没有单独的子路径导出:按需引入依靠 tree-shaking,不依靠手写路径。
