Monorepo(单仓库)和 Multirepo(多仓库)分别代表了两种不同的源代码管理策略。
mono 源自希腊语,单个 ; multi 单词前缀,表示多
repo 是 repository 的缩写
演进阶段
阶段一: 单仓库巨石应用, 一个 Git 仓库维护着项目代码,随着迭代业务复杂度的提升,项目代码会变得越来越多,越来越复杂,大量代码构建效率也会降低,最终导致了单体巨石应用,这种代码管理方式称之为 Monolith。
阶段二: 多仓库多模块应用,于是将项目拆解成多个业务模块,并在多个 Git 仓库管理,模块解耦,降低了巨石应用的复杂度,每个模块都可以独立编码、测试、发版,代码管理变得简化,构建效率也得以提升,这种代码管理方式称之为 MultiRepo。
阶段三: 单仓库多模块应用,随着业务复杂度的提升,模块仓库越来越多,MultiRepo这种方式虽然从业务上解耦了,但增加了项目工程管理的难度,随着模块仓库达到一定数量级,会有几个问题:跨仓库代码难共享;分散在单仓库的模块依赖管理复杂(底层模块升级后,其他上层依赖需要及时更新,否则有问题);增加了构建耗时。于是将多个项目集成到一个仓库下,共享工程配置,同时又快捷地共享模块代码,成为趋势,这种代码管理方式称之为 MonoRepo。
一些想法:MonoRepo 不一定是要将所有组件放一起,可以将同类型业务以统一仓库的形式管理。从业务视角将分散的组件,拼成几大类仓库。比如营销Repo、会员Repo等
Monorepo(单仓库)
# monorepo目录结构:公共依赖 + 每个子包的独立依赖
|-- monorepo-demo
| |-- packages # packages目录
| | |-- compiler # compiler子包
| | | |-- package.json # compiler子包特有的依赖
| | |-- reactivity # reactivity子包
| | | |-- package.json # reactivity子包特有的依赖
| | |-- shared # shared子包
| | | |-- package.json # shared子包特有的依赖
| |-- package.json # 所有子包都公共的依赖
优点:
- 统一的版本管理:所有项目或包使用相同的依赖版本,避免了依赖地狱。
- 代码重用非常容易:由于都在一个仓库下,很容易抽离出各个项目共用的业务组件或工具。
- 避免重复安装包:减少了磁盘空间的占用,并降低了构建时间;内部代码可以彼此相互引用;
缺点:
- 仓库大小:随着时间推移,Monorepo 可能会变得非常大,影响克隆和拉取的速度。
- 权限和安全性:项目粒度的权限管理变得非常复杂,需要精细管理权限。
- 新人学习成本高:原来一个项目一个仓库,现在n个项目一个仓库,新人需要理清各个代码仓库之间的相互逻辑。
使用场景:
- 大型组织,需要跨团队和项目进行协作的情况。
- 对项目之间的一致性和同步有高要求的环境。
- 需要频繁共享代码和进行协作的项目组合。
Multirepo(多仓库)
# multirepo-a目录结构:每个项目依赖隔离,独立存在
|-- multirepo-a
| |-- src
| | |-- feature1 # feature1目录
| | |-- feature2 # featrue2目录
| |-- package.json # 整个项目依赖
# multirepo-b目录结构
|-- multirepo-b
| |-- src
| | |-- feature3 # feature3目录
| | |-- feature4 # featrue4目录
| |-- package.json # 整个项目依赖
优点:
- 灵活性:每个项目可以独立管理,有自己的构建、测试和部署流程。
- 细化权限控制:更容易对不同项目设置不同的访问权限。
- 易于维护:项目较小,易于管理和维护。
- 规模可控:项目的大小不会影响仓库的性能。
缺点:
- 依赖管理复杂:需要跨仓库管理和协调依赖版本。
- 代码重复:不同项目中可能会出现重复代码。
- 协作难度:跨仓库的更改需要协调,可能导致集成问题。
- 版本不一致风险:不同项目使用的组件版本可能不一致,增加了集成和测试的复杂性。
使用场景:
- 较小的团队或项目,不需要频繁地跨项目协作。
- 每个项目的依赖和构建流程差异较大,需要独立管理。
- 对项目的隔离性和安全性有较高要求。
结论
一般来说
- 大型开源库,例如 Babal 以及 Vue3 等等都会选择使用 Monorepo
- 而日常业务中,通常都是项目制的,通常会选择 Multirepo
差别
-
Monorepo 目录中除了会有公共的 package.json 依赖以外,在每个 sub-package 子包下面,也会有其特有的 package.json 依赖。
-
Multirepo 更倾向与在项目制中,将一个个项目使用不同的仓库进行隔离,每一个项目下使用独有的package.json 来管理依赖。
参考引用