monorepo 和 multirepo
一般大到分项目,小到写代码,都遵循着拆分的原则,尽量不在一个项目、方法里糅合太多的东西。对于这种管理仓库的风格,称之为 multirepo
。这样做的好处是,按不同项目可以分为多个仓库,仓库之间保证独立,独立开发独立部署,保证了每个项目之间不受其他项目影响。
另一种风格就是 monorepo
了,也就是把多个项目放到一个仓库中,虽然把所有东西放到一起听起来很糟糕,但不仅仅是这样。对于 monorepo
而言,你只是把多个项目按你所设的某种场景把它组织到了一起,它的粒度还是保持原有的划分,对于某个团队的某个开发人员而言,他的关注点还是在其中一个项目。可能听上去这种方式相对于 multirepo
而言有些多此一举,我已经把仓库拆分了,为何还要再组织回去呢?对于一些前端项目而言,它的确有组织回去的好处,接下来就具体分析一下。
monorepo
并不是一种工具,它只是对于项目的一种管理手段,一种思维方式。
monorepo 的优点
简化组织
很大一部分情况下,我们在一开始开发项目的时候并不能保证项目的规模只有这么大,随着不断的迭代业务会越来越多,逻辑越来越复杂,于是就要对项目进行拆分。又或者是几个不同的但都处于某一块业务的项目。用这时候使用 monorepo
的方式来管理这些项目,能够简化项目结构组织。用 Dan Luu(参考文档三)的观点来说,很多拆分都不是正确的拆分。可能只是因为代码量多,或其他非必要原因对仓库进行了拆分。那就需要再重新将他们组织回来。
减少重复依赖项
对于前端项目,npm install
,npm run dev
这些步骤已经刻在我们的基因里了。但是 install 安装了庞大的 node_modules
后,其实大部分项目所安装的库都有重复。那我们应该把这些依赖项提取出来,而都引用了这些依赖的子项目只需要通过软链接这样的方式引入依赖项即可。
跨项目开发
如果我们同时在给几个 npm 模块进行功能迭代开发,在多个仓库下调试起来可能不是那么方便,还需要手动维护 npm link
,通过 monorepo
可以直接在本地进行夸项目间的联调,提高开发的效率。
更方便的仓库管理
对于一些大型、开源的项目来说,多个仓库意味着你要在多个地方进行 issue 之类的处理,你会更倾向于统一这些类似的 issue,管理很多 PR 和 git 钩子等等。
实践
Lerna
前面有讲过,既然 monorepo
不是工具,那我们就需要一个工具来实现它,在参考了一些文章后,我决定使用 Lerna(参考文档二)。
A tool for managing JavaScript projects with multiple packages.
这是 Lerna 官网对于它作用的描述,用来管理多个 JS 项目。不仅可以用 Lerna 来实现对多个项目仓库的管理,也可以用来管理多个 npm 包的维护发布。vue-cli(参考文档五),Babel(参考文档六)等知名项目也使用了 Lerna,大佬们都用了,那我们跟着梭哈就完事儿了。
然后我们只要通过命令 npm install --global lerna
将 Lerna 安装到全局。然后就可以开始了。
通过命令 lerna init
来初始化 Lerna 的目录,初始化完可以看到目录特别简单:
- packages
- package.json
- lerna.json
我们只要把项目放到 packages 文件夹下面即可。
在 lerna.json
中就是对 Lerna 的一些配置了,package.json
是用来管理主仓库的依赖之类的。
lerna.json
{
"npmClient": "npm",
"packages": [
"packages/*"
],
"version": "0.0.0"
}
npmClient
指定了安装使用的方式,可以用 npm 也可以用 yarn。packages
里面定义了子项目的路径,可以根据你想要的逻辑自由定义路径。
那么接下来就要实现一下刚才提到的关于依赖项的优化,Lerna 提供了一个命令:lerna bootstrap
来安装所有 package 的依赖项。运行这个命令相当于给每个项目都运行了 npm install
。可我们想