在现代全栈项目中,前端、后端、共享库与工具脚本往往交织在一起。随着功能增长和团队扩张,如果仍采用多个独立仓库(Polyrepo)模式,就会遇到:
- 共享模块版本不一致
- 引用混乱、类型不对齐
- 跨项目重构难以保持一致
- 配置分散、难以维护
在这样的背景下,Monorepo(将多个子项目共置于同一个仓库)成为一个极具吸引力的方案。
不过,"Monorepo 适合所有项目"是一个误区。下面将依次介绍:
- 适用场景
- PawHaven 的选择逻辑
- 架构设计与目录结构
- 配置复用实践
一、什么场景下适合使用 Monorepo?
Monorepo 有明确的适用边界。以下场景通常能发挥它的最大价值:
适用场景 | 原因 |
---|---|
多个子项目 / 模块强耦合 | 需要共享类型、DTO、工具函数等 |
频繁跨模块改动 / 重构 | 一次 commit 可同时修改多个子项目 |
团队规模可统一协调 | 各模块协作频繁、节奏一致 |
希望统一 CI/CD 流程 | 可共用 pipeline、缓存与任务依赖 |
希望配置和工具链复用 | ESLint / tsconfig / style 配置集中管理 |
想降低版本冲突 | 同仓依赖更容易保持一致版本 |
不适合的情况:
- 项目体量小,模块关系简单
- 模块之间几乎无共享逻辑
- 技术栈差异大、配置难统一
- 团队权限隔离严格、协作较少
Monorepo 的挑战也需正视:
仓库体积扩大后,构建、克隆、CI 时间可能变长;
访问控制、依赖边界、工具链配置也更复杂。
✅ 结论:Monorepo 不是"高级"的代名词,而是要在权衡收益与复杂度后谨慎选择。
二、为什么 PawHaven 选择 Monorepo?
PawHaven 是一个由 React 前端 + NestJS 后端 + 共享库 组成的全栈项目。
选择 Monorepo 的原因主要有以下几点:
1. 共享类型、DTO 与工具函数
前后端共享的接口、常量、类型在同仓库内统一维护,可通过 TypeScript 的路径 alias 或 workspace 引用,避免重复维护。
2. 统一配置管理
ESLint、tsconfig、Tailwind 等配置集中管理,子模块直接继承,保持一致性并降低维护成本。
3. 跨包改动一次提交
当 shared 组件、DTO 类型或后端接口需要同步修改时,可以在一条 PR 内完成,保证版本一致。
4. 集中化的 CI/CD 流程
统一定义构建、测试、部署流程,共享缓存与工具链,简化持续集成维护。
5. 依赖去重与版本一致性
通过 pnpm
的 hoist 机制,所有子包共用相同版本的依赖库,避免冲突。
6. 统一入口,降低沟通成本
对于开源项目来说,无论是开发、文档还是对外宣传,一个仓库即代表整个项目,减少多仓库间的沟通与管理负担。
三、Monorepo 的结构设计与 PawHaven 实践
设计原则
- 业务与非业务代码分离:将可部署应用与共享库明确划分
- 配置集中化:ESLint、tsconfig、Tailwind 等放在独立配置库中
- 结构一致性 :每个子包的目录规范统一(
src/
,tsconfig.json
,package.json
) - 路径简洁化:使用 alias / workspace 引用,而非相对路径层层跳转
- 工具链兼容性:构建、类型检查、Lint 均支持跨包路径
🧭 PawHaven 的目录结构
js
├─ pnpm-lock.yaml
├─ pnpm-workspace.yaml
├─ apps
│ ├─ backend
│ │ ├─ gateway
│ │ ├─ ms-auth
│ │ ├─ ms-document
│ │ └─ ms-pawhaven
│ └─ frontend
│ ├─ user
│ └─ admin
├─ packages
│ ├─ shared-frontend
│ ├─ i18n
│ ├─ shared-backend
│ ├─ theme
│ └─ ui
├─ libs
│ └─ configs
│ ├─ eslint-config
│ └─ tsconfig
├─ .vscode/
│ ├─ settings.json
│ └─ extensions.json
目录说明:****
- apps/:前端与后端独立业务模块
- packages/:与业务相关的共享模块(UI、主题、i18n、shared types)
- libs/:工具类与配置类库,可独立发布
四、统一配置设计(ESLint / tsconfig / Tailwind)
1️⃣ ESLint 配置
目标:实现 Web 与 Node 环境下的统一规范。
实现方式:
- 在 libs/configs/eslint/ 中集中维护配置;
- 根据运行环境区分 eslint-config-web 与 eslint-config-node;
- 各子包直接在 .eslintrc.cjs 中继承使用,可按需覆盖。
📦 具体实现和用例:PawHaven/libs/eslint
2️⃣ tsconfig 配置
目标:统一 TypeScript 编译选项,并支持多目标(web / node)。
实现方式:
-
在 libs/configs/tsconfig/ 中定义 base.json 与各场景扩展;
-
各子项目仅需继承并覆盖输出路径、rootDir 等关键项。
📦 具体实现和用例:PawHaven/libs/tsconfig
3️⃣ Tailwind 设计系统
目标:保持所有前端包与组件库的样式一致性。
实现方式:
- 在 packages/theme/ 中集中维护 Design Tokens 与全局配置;
- UI 组件库与前端应用共享主题;
- 确保内容扫描路径包含共享组件库的文件。
📦 具体实现和用例:PawHaven/packages/theme
五、总结
PawHaven 通过 Monorepo 架构实现了:
-
多模块集中管理与协作开发
-
ESLint、TypeScript、Tailwind 的统一配置
-
前后端类型共享与依赖一致性
-
提高开发效率与项目可维护性
✅ 核心启示:Monorepo 并非为了"高级",而是为了"协调"。
在确定采用之前,应充分评估项目规模、团队结构与维护成本。
💡 延伸阅读 & 开源实践****
更多关于前端、后端与 Monorepo 的企业级实践,欢迎 Star 或 Watch 我的仓库: