Contents
[NOTE] Updated May 31, 2023. This article may have outdated content or subject matter.
当项目变得庞大的时候,自然就会想到去拆分,以更小的单位去维护,或者复用。
一种组织方式是,将项目拆成多个独立的 repo,然后通过子模块关联,
或者将某些模块发到 npm,通过 npm 去安装依赖。
这种拆分成多个 repo 的组织形式,称为 multirepo
,这种组织形式的有什么优劣呢?
multirepo 优缺点
优点
-
每个仓库的大小一般不会很大
-
每个仓库独立,可以单独对仓库进行权限控制, 例如控制谁有权限访问,谁可以提交等。
缺点
-
当维护多个 repo 时,需要在多个 repo 之间切换,容易混乱。
-
每个仓库可能有一套自己的配置,仓库之间不兼容,标准不统一。
-
repo 和子模块可能存在重复的依赖,导致依赖的重复安装。
-
不在同一个 repo 中,不方便分析整个项目的所有依赖。
-
发布的时候,如果多个 repo 存在依赖关系,要按照依赖顺序依次构建再部署。
-
repo 之间存在依赖关系,调试依赖的仓库时,需要 npm link 关联仓库。
面对 multirepo 的这些问题,就有人提出了 monorepo
的组织方式。
A monorepo is a single repository containing multiple distinct projects, with well-defined relationships.
一个 monorepo 应该是:
-
单一的仓库
-
仓库中包含多个独立的项目
-
每个项目之间的关系定义清晰明确
简单的理解,monorepo 就是把原来的 multirepo 合并成一个 repo。
那是不是把每个 repo 分别放到不同的目录,建一个新的庞大的仓库,就完事了呢?
这样就变成一个“大杂烩”了,被称为 Single-repo Monolith
, 已经接近 monorepo 的样子了。
在这个基础上,还需要:
-
每个 repo 逻辑上独立,项目之间可能是不相关的,松散连接的,或者可以通过一些方式连接起来。(譬如 pnpm 的 workspace)
-
要保证项目之间的依赖关系定义清晰
-
项目间的依赖关系 :
项目之间存在依赖时,不需要人工按照拓扑排序进行 link,
而是有一定程度的自动化,通过一些简单的配置,可以自动完成 link。
例如每个项目配置好 package.json, 定义依赖关系,然后自动分析 package.json,自动完成项目之间的关联 -
项目第三方依赖间的关系 :
多个项目中,相同的依赖应该只安装一次;
版本不同的依赖需要解决好冲突,例如一些对单例有要求的依赖(react)
对于 项目间的依赖关系 ,为了实现一定程度的自动化,需要借助一些工具,如 NX,Lerna,turborepo。
对于 项目第三方依赖间的关系, 可以借助 yarn,pnpm 等包管理工具的 workspace 功能去实现。
所以,有别于 Single-repo Monolisth, monorepo 需要有明确清晰的依赖关系,能够很方便地管理依赖。
-
优点
-
更容易管理依赖
-
源码都在一起,方便调试
-
可以在多个模块中,复用相同的配置,例如单元测试,CI/CD 相关的配置,便于保持规范一致
-
由于相关的项目都在一起,因此可以比较方便地编写集成测试
-
当有一个功能,牵涉多个模块时,可以在一个提交中改好,而 multirepo 则需要在多个 repo 做提交
缺点
-
项目启动,打包构建速度变慢
-
当项目很庞大,提交记录很多时,git 的一些操作性能上会变慢
-
没法限制不同模块的访问权限。也是一个优点,开发人员能看到所有模块,了解到这些模块的关联,而不是只关注自己的模块。
-
可能出现"幽灵"依赖,由于依赖安装在项目的 root 目录,所有模块能访问到, 于是即使模块中忘了声明某个依赖,但是 root 中存在,则可以使用。但实 际部署时,会因为没有声明依赖,导致没有安装而报错。
-
Monorepos By Example: Part 1
一个应用 monorepo 的例子。用 Lerna 管理依赖。 -
Spike-Leung/leetcode
我自己的实践,分成了 solutions, solution-parser, web 三个 package, 然后用 pnpm 的 workspace 关联,比较简单,没用到 monorepo 的工具。 -
illa-design
一个组件库,组件之间就是以 monorepo 的形式组织的,目前 使用的工具是 turborepo -
vuejs/core
看起来也是一个 monorepo 的组织方式,使用了 pnpm 去管理依赖
-
monorepo.tools
对 monorepo 的整体介绍,同时比对了不同 monorepo 工具之间的优缺点 -
Monorepo 的过去、现在、和未来
解释了 monolith 和 moporepo 间的差别,怎么实现这些差别,以及相关的 工具,比较了作者自己用到的一些工具 -
开源项目都在用 monorepo,但是你知道居然有那么多坑么?
对比了 multirepo 和 monorepo 的优缺点,较详细地分析了 monorepo 带 来的问题:依赖,构建,测试,发布等 -
Guide to Monorepos for Front-end Code
讲了为什么要用 monorepo,monorepo 的优劣,以及实现 monorepo 的 工具链 -
Awesome Monorepo
整理了 monorepo 相关的工具 -
JavaScript package managers compared: npm, Yarn, or pnpm?
比对了常用的包管理工具: npm vs yarn vs pnpm, 提及他们对 monorepo 的支持 -
Exploring the Typescript Monorepo (a practical, hands-on adventure)
Monorepo 引子,作为目录管理和 multirepo 管理的折中模式,同时包含一些实践。