来源：https://ui.docs.xihanfun.com/npm-package-dependency

# 包与依赖关系

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` 门禁保证。

::: tip 开发期第三方依赖另行处理
`@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，不依靠手写路径。


## 相关

- [架构总览](./overview#分层与依赖矩阵)
- [安装与接入](./installation)
- [测试与质量门禁](./guide/testing#结构门禁)
