Monorepo架构

Monorepo 单仓库多项目架构

#tech / dev / pattern #type / concept #status / growing

Monorepo 架构

一句话定义

Monorepo 是将多个项目(应用、库、服务)放在同一个代码仓库中,通过共享依赖和统一工具链来管理的代码组织策略。

核心机制 / 工作原理

Monorepo vs 多仓库(Polyrepo)

维度MonorepoPolyrepo
代码复用直接引用本地包,零发布成本需发布 npm 包再引用
原子提交一个 PR 可同时修改多个包跨仓库需多个 PR 协调
统一版本所有包共享同一 git 历史各仓库独立版本管理
依赖管理统一提升,避免重复安装各自 node_modules,体积膨胀
CI/CD需要增量构建,配置更复杂每个仓库独立流水线,简单直接
权限控制粒度粗(目录级)粒度细(仓库级)
仓库体积随项目增长会很大各自独立,体积可控

核心挑战

1. 构建速度

随着包数量增加,全量构建时间线性增长。解决方案:

  • 增量构建:只构建有变更的包及其依赖链
  • 任务缓存:相同输入跳过重复构建(local cache + remote cache)
  • 并行构建:无依赖关系的包并行执行

2. 依赖管理

  • 需要 workspace 机制避免重复安装依赖
  • 包之间的版本对齐问题
  • Phantom dependency(幽灵依赖):未声明但因提升机制可访问的包

3. 代码边界

  • 没有强制约束时,包之间可能产生不合理的耦合
  • 需要 lint 规则或工具强制执行依赖方向

工具链

工具定位特点
pnpm workspace依赖管理硬链接节省磁盘,严格依赖隔离
Turborepo任务编排增量构建 + 远程缓存,配置简单
Nx全功能平台依赖图分析、增量构建、affected 检测、插件生态
Lerna包发布多包版本管理、changelog 生成(已被 Nx 团队接管)
Bazel/Buck大规模构建Google/Meta 级别的构建系统,学习曲线陡峭

典型目录结构

monorepo/
├── apps/
│   ├── web/            # 前端应用
│   ├── api/            # 后端服务
│   └── mobile/         # 移动端
├── packages/
│   ├── ui/             # 共享 UI 组件
│   ├── utils/          # 工具函数
│   ├── config/         # 共享配置(ESLint、TS)
│   └── contracts/      # API 契约
├── package.json        # workspace 根配置
├── pnpm-workspace.yaml
└── turbo.json          # Turborepo 配置

最小例子

pnpm workspace 配置:

# pnpm-workspace.yaml
packages:
  - "apps/*"
  - "packages/*"
// apps/web/package.json
{
  "dependencies": {
    "@myorg/ui": "workspace:*",
    "@myorg/utils": "workspace:*"
  }
}

pnpm install 会自动将 packages/uipackages/utils 链接到 apps/web/node_modules,无需发布即可引用。

边界与常见误解

  • Monorepo 不是单体应用:代码在一个仓库,但部署仍是独立的服务/应用
  • 不是所有项目都适合:3 人以下团队、2-3 个项目时,Polyrepo 更简单
  • Git 大文件问题:单仓库积累大量二进制文件会拖慢 clone;需用 Git LFS 或定期清理
  • CI 复杂度被低估:需要 affected 检测、远程缓存、并行执行,否则 CI 时间会膨胀
  • 权限控制有限:GitHub 等平台不支持目录级权限,敏感代码可能需要拆分
  • Phantom dependency:pnpm 通过严格模式解决,npm/yarn 默认的提升机制会产生幽灵依赖

Contracts 在 Monorepo 中的角色

在 DDD 架构下,Contracts 包负责:

  • API 契约:前后端通信的数据格式
  • 数据验证:Zod Schema 用于请求验证
  • 序列化格式:去除敏感信息的安全数据传输
  • 版本控制:API 接口的版本管理

Domain 包负责业务逻辑和领域概念,两者职责不同。

创建于 2025/8/10 更新于 2026/5/27