前言
该笔记主要是基于《全栈Monorepo开发实战》这本书的一个阅读和实践记录,适合对使用TypeScript实现Monorepo项目感兴趣以及计划在项目中实践Monorepo项目的前端开发工程师,需要了解更细节的内容可以自行去找这本书来阅读。
实战中涉及到的技术栈:Vue3+Fastify+Deno+pnpm
第1章 Monorepo架构
简介
Monorepo的诞生可以追溯到2000年初,mono指的是single,即单;repo就是repository,即仓库;虽然mono是single的含义,但与Single-repo的区别是,Single-repo指的是一个代码仓库只有一个项目,而Monorepo是一个代码仓库管理了多个项目。
谷歌是最早实现Monorepo架构的公司之一,也是世界最大的Monorepo仓库之一,有20亿行代码,每天有数万名工程师进行40000+次提交
2022年JavaScript年度调研报告里首次出现Monorepo管理/构建工具排行榜,可以从JavaScript GitHub的Star年度涨幅排行榜中看到很多影响力非常高的开源项目开始使用Monorepo架构管理代码,例如Vite、React、Vue3、Babel、Next、Nuxt等。
1.1 常用的代码组织架构
1. Single-repo
即一个应用的所有代码全放在一个代码仓库中管理,模块之间仅仅通过简单的划分或划分来进行组织,例如在项目中常见的分模块目录结构:Lib、Utils、View。
这种项目通常会随着业务的不断扩展和迭代,逐渐形成Monolith(巨石)应用,整个应用就像一个独立的npm包,只在根目录有一个package.json文件,用来管理项目的版本和依赖关系。例如Vue2项目就是一个由Yarn管理的Single-repo项目,目录结构如下:
vue
├── src
│ ├── compiler
│ ├── core
│ ├── server
│ ├── share
│ └── platforms
...
└── package.json
2. Multirepo
即多代码仓库,是一种把应用内的各模块进行单独隔离和封装的方法,每个模块都存放在独立的代码仓库中进行管理。相当于在Single-repo的基础上,将公共模块放在单独的代码仓库进行隔离和发布,例如Util库、UI库和Cli库等,每个模块都有一个代码仓库和对应的package.json进行包的管理。
每个代码仓库都有独立的版本号管理,依赖管理、CI/CD流程。优点如下:
- 与项目进行解耦
- 可单独发布提供给多个项目使用
- 便于模块的单独管理和维护
3. Monorepo
Monorepo相当于是在Single-repo上实现Multrepo的优点和特性,即Monorepo项目中的各个子项目与Multirepo一样,进行彻底的隔离和封装,但是只需要在同一个仓库中进行管理。
例如Vue3就是一个由pnpm管理的Monorepo项目,其目录结构如下:
vue/core
├── packages
│ ├── compiler
| | | ...
| | └── package.json
│ ├── compiler-dom
| | | ...
| | └── package.json
│ ├── vue
| | | ...
| | └── package.json
...
│ ├── package.json
└── pnpm-workspace.yaml
packages目录下的每一个目录都是一个完备的npm包,并且统一进行版本管理。
🔑 代码架构对照表
| 仓库架构 | Single-repo | Multirepo | Monorepo |
|---|---|---|---|
| Repo数量 | 一个 | 多个 | 一个 |
| package.json数量 | 一个 | 一个仓库一个 | 工作空间目录一个,一个模块一个 |
Monorepo的优缺点
1. 有助于更好、更高效的工作流程
这种可见性使开发者更容易地进行跨系统、应用程序、库的程序搜索、共享和代码复用。随着代码复用和可见性的提高,代码一致性也会提高。
2.更容易管理应用内部之间的依赖关系
Monorepo由多个应用程序和库组成,这种组织方式可以更好地检查包之间的关系,更容易地进行全局重构。例如将A项目中的函数移动到B库中,或者将B库拆分成若干小库。这些操作只需要在IDE中移动目录,修改错误并调试即可完成。但缺点也是很明显,需要对项目涉及的所有方面有足够了解,一般不建议这么操作,即不轻易地修改存量代码,否则可能造成不可预期地损失。
3. 提供统一的Git提交视图
Monorepo项目中,由于所有提交在同一个仓库中,因此更容易分析当前应用整体Git提交情况。
4. 便于统一CI/CD、打包等自动化构建和测试流水线
Monorepo的优势在于将所有代码放在一起,有利于进行测试自动化。由于代码、工具和配置都在一起,可以更容易地统一管理所有配置信息,比散落在多个仓库中的配置文件更容易维护。
5. 可以极大简化依赖的管理
当项目变复杂时,非常清晰的单一模块依赖已经变得不那么重要,更重要的是在全局上统一管理依赖关系。
6. 降低多技术融合的成本
Monorepo支持多种流行技术,并且可以很容易地进行融合,例如一个pnpm项目中是可以集成Rust workspace或者Go workspace项目。使用Rust编写CLI,再通过pnpm发布,其他项目使用起来会变得非常简单。
Monorepo的缺点
1. 相关开发工具不成熟
Monorepo是近年流行起来的一种开发方式,相关工具链和IDE仍在适应和调整阶段。Git在处理大型Monorepo项目时的性能也不尽如人意。
2. CI/CD流水线较为复杂
由于有太多项目依赖的包和模块,构建需要太多的步骤,可能导致迭代停滞不前。任何改动都需要重新构建整个Monorepo项目,而不是只构建应用程序的一部分。需要深入了解代码库之间的关系,并编写自动化流程。
3. 测试复杂
测试和通常的构建/编译任务必须按照正确的顺序完成,才能确保所有依赖项从正确的来源构建并在正确的时间可用。
4. 固有的复杂性
管理Monorepo项目非常复杂,需要解决很多问题,而且容易出错。定制协调和自动化脚本需要花费相当长的时间去学习使用。
5. 权限的管理性差
因为如Git或Mercurial等系统缺少内置目录权限。通常需要在一个目录下面维护一个Markown文档来指明负责人。