2026-08-26 16:20:55 +08:00

2.3 KiB
Raw Blame History

ADR-005: Monorepo 布局pnpm workspaceapps/server + apps/web + packages/shared

Status: Accepted (2026-08-26)

Background

后端Express与前端Vue3同用 TypeScript且有大量共享的领域类型由 zod schema 经 z.infer 产出、zod 数据 schema、统一响应 ApiResponse<T>、错误码、枚举。若前后端各自复制一份类型定义,一旦模型变更会出现「同一模型多处漂移」,违背 spec-as-contract契约应单点可寻址

Decision

采用 pnpm workspace 单仓多包

gwy-exam/
├── pnpm-workspace.yaml
├── package.json                 # 仅脚本 + workspace不装业务依赖
├── tsconfig.base.json           # 共享 strict 编译基座
├── apps/
│   ├── server/                  # Express 5 + TS + ESM
│   └── web/                     # Vue3 + Vite + TS
└── packages/
    └── shared/                  # 领域类型 + zod schema + ApiResponse + 枚举 + 常量

类型契约、zod schema、ApiResponse<T>、错误码联合全部放 packages/sharedapps/serverapps/web 通过 workspace 引用共享。

为什么选 monorepo 而非独立仓

  1. 前后端同 JS/TSpackages/shared 是天然共享层,独立仓需额外发布/维护两份。
  2. 契约类型单点维护防漂移spec-as-contract契约可寻址、可审计
  3. 一次 pnpm install、一次 CI开发与验收路径单一。

分层依赖(对照 code-organization.md

  • apps/server 依赖 packages/shared(向下)。
  • apps/web 依赖 packages/shared(向下)。
  • packages/shared 不依赖任何 app,保持纯净、可被任何一方 import 而无环。

Consequences

  • 正面:类型单一来源、契约一致、前后端并行开发不踩、一次安装。
  • 负面:单仓体积稍大;packages/shared 须保持无业务、无 app 依赖(否则环),需纪律约束。
  • 权衡个人工具规模下monorepo 的成本(配置 pnpm workspace + 共享 tsconfig远低于收益类型一致性。若未来拆出多应用可无损演进。
  • ADR-001Express/ ADR-002Vue+Vite
  • ADR-004全 TS strict — 与 shared 类型强绑定)
  • ADR-006垂直切片 — shared 作为单一契约源的承载层)