单仓库模块管理,可使用 lerna 进行包管理
monorepo 是一种将多个项目代码存储在一个仓库里的软件开发策略(“mono” 来源于希腊语 μόνος 意味单个的,而 “repo”,显而易见地,是 repository 的缩写)

monorepo 的优劣势

通过 monorepo 策略组织代码,您代码仓库的目录结构看起来会是这样:

.
├── lerna.json
├── package.json
└── packages/ # 这里将存放所有子 repo 目录
    ├── project_1/
    │   ├── index.js
    │   ├── node_modules/
    │   └── package.json
    ├── project_2/
    │   ├── index.js
    │   ├── node_module/
    │   └── package.json
    ...

乍看起来,所谓的 monorepo 策略就只是将不同项目的目录汇集到一个目录之下,但实际上操作起来所要考虑的事情则远比看起来要复杂得多。

优点

  • 项目代码可集中进行管理,使用统一的构建工具。
    代码重用将变得非常容易:由于所有的项目代码都集中于一个代码仓库,我们将很容易抽离出各个项目共用的业务组件或工具,并通过 TypeScriptLerna 或其他工具进行代码内引用;
  • 依赖管理将变得非常简单:同理,由于项目之间的引用路径内化在同一个仓库之中,我们很容易追踪当某个项目的代码修改后,会影响到其他哪些项目。通过使用一些工具,我们将很容易地做到版本依赖管理和版本号自动升级;
  • 代码重构将变得非常便捷:想想究竟是什么在阻止您进行代码重构,很多时候,原因来自于「不确定性」,您不确定对某个项目的修改是否对于其他项目而言是「致命的」,出于对未知的恐惧,您会倾向于不重构代码,这将导致整个项目代码的腐烂度会以惊人的速度增长。而在 monorepo 策略的指导下,您能够明确知道您的代码的影响范围,并且能够对被影响的项目可以进行统一的测试,这会鼓励您不断优化代码;
  • 它倡导了一种开放,透明,共享的组织文化,这有利于开发者成长,代码质量的提升:在 monorepo 策略下,每个开发者都被鼓励去查看,修改他人的代码(只要有必要),同时,也会激起开发者维护代码,和编写单元测试的责任心(毕竟朋友来访之前,我们从不介意自己的房子究竟有多乱),这将会形成一种良性的技术氛围,从而保障整个组织的代码质量。
  • 模块间调试方便、问题定位和修复相对容易

缺点

  • 仓库体积大,对构建工具要求较高
    • 对于公司级别的 monorepo 策略而言,需要专门的 VFS 系统,自动重构工具的支持:设想一下 Google 这样的企业是如何将十亿行的代码存储在一个仓库之中的?开发人员每次拉取代码需要等待多久?各个项目代码之间又如何实现权限管理,敏捷发布?
  • 项目粒度的权限管理变得非常复杂:无论是 Git 还是其他 VCS 系统,在支持 monorepo 策略中项目粒度的权限管理上都没有令人满意的方案,这意味着 A 部门的 a 项目若是不想被 B 部门的开发者看到就很难了。
  • 为了保证代码质量,对版本控制和 Git 工作流要求更高
  • 新员工的学习成本变高:不同于一个项目一个代码仓库这种模式下,组织新人只要熟悉特定代码仓库下的代码逻辑,在 monorepo 策略下,新人可能不得不花更多精力来理清各个代码仓库之间的相互逻辑,当然这个成本可以通过新人文档的方式来解决,但维护文档的新鲜又需要消耗额外的人力;

单页应用类似

比较维度NxLernaNpm WorkspacesYarn Workspaces
初衷专注大型前端 Monorepo,内置任务调度和构建缓存传统 Monorepo 工具,提供发布流程与版本管理npm 原生多包管理,降低配置成本基于 Yarn,强调性能与依赖缓存
依赖管理内置工作区依赖处理,支持受控版本可配置 hoist/nohoist,需在 lerna.json 中手动设置默认会将依赖提升到根目录,可用脚本自定义同样会进行依赖提升,可配置 nohoist
版本/发布可结合 Nx CLI 或其他工具(如 release-it)来发布内置版本管理与发包功能,支持自动打标签与语义化版本多包版本独立,需手动执行 npm publish多包版本独立管理,可结合 Yarn CLI 或脚本完成发布
构建能力内置统一任务调度与缓存,适合大型前端项目无内置构建功能,主要依赖第三方脚本或配置仅提供多包管理,不负责构建流程同样不内置完整构建功能,偏重依赖管理
适用场景大型、复杂 Monorepo,需要统一构建和高效任务编排中大型多包项目,需自动化版本与灵活依赖管理小型或中型多包项目,偏好使用 npm 工具链中型或有性能需求的多包项目,偏好 Yarn 的依赖缓存与快速安装
入门难度略高,需学习 Nx-specific 配置与 CLI中等,需要掌握命令行与 lerna.json 配置低,与 npm 原生流程一致,几乎无需额外学习低,与 Yarn 命令类似,但需熟悉 Yarn 的自定义配置
主要优势任务图、构建缓存、可扩展性强,支持多框架(React 等)历史悠久,生态成熟,自动化发布、Changelog 生成等功能齐全无需额外插件即可上手,原生支持安装快(依赖缓存)、配置灵活,社区插件多
主要劣势学习和配置成本较高,文档相对 Lerna 稍少构建优化与任务编排不如 Nx无高级发布功能,需要外部工具配合高级 Monorepo 功能不如 Nx/Lerna,需组合其他工具完成发布等

monorepo实践

参考资料