什么是monorepo?为什么大厂前端都在用它?

276 阅读5分钟

1、什么是monorepo?

monorepo,即在单个仓库(如Git)中存储多个项目代码的软件开发策略。这些项目通常具备一定的独立性,承载不同的功能场景,并由不同的团队维护。

极端情况下,配套专用的构建工具,monorepo可以存放不同语言、不同构建方式的项目代码。

mono,来源于希腊语μόνος,表示“单个”。monorepo = mono + repository。

可以说,monorepo并非某种技术实现,正如上面对其定义一样,monorepo仅仅是一种开发策略,如何实现monorepo并没有技术上的限制。

2、为什么会提出monorepo概念?

2.1 场景1:“分久必合”

某业务包含多个同技术栈项目,这些项目分属不同Git仓库。随着业务扩大,复杂度提升,同时对这些项目进行维护、测试、部署、依赖处理会造成成本逐渐提升。

与此同时,开发者不停的在代码风格、框架、环境配置不尽相同的项目切来切去,造成了一定的心智负担。

于是,小美考虑是否有一种方法,可以让我在同一处就可以看到所有负责的代码库,并且可以有统一的工程方案辅助完成开发构建。

常见场景:微前端、前后端一体项目、跨端项目。

2.2 场景2:“合久必分”

如果你开发了一套UI组件库,其他人若要引用你的UI组件库,必须在项目中安装完整的UI组件库包。随着技术更迭,社区期望可以单独安装组件库某个组件,而非全量引入。

于是,你考虑将组件库进行重构拆分,在单仓库中,将原代码拆分为多个单独UI的npm包。

2.3 “合久必分、分久必合”演化monorepo策略

总结来讲,合久必分遇到的是单仓库单项目功能单一的问题,分久必合遇到的是天然隔离独立的多仓库如何融合的问题。

这些场景演化出了monorepo开发策略,借助monorepo仓库中心化的思想,如果能解决单一仓库管理、多包统一构建等工程问题,“合久必分、分久必合”遇到的场景困境将迎刃而解。

3、单仓库(monorepos) vs 多仓库(multirepos)

monoerpo:是把所有相关的 package 都放在一个仓库里进行管理,每个 package 独立发布。例如:React, Angular, Babel, Jest, Umijs, Vue 等。

mutlirepo:是比较传统的做法,即每一个 package 都单独用一个仓库来进行管理。例如:Rollup。

对于多仓库(多代码库)而言,虽然拆分子仓库、拆分子 NPM 包(For web)是进行项目隔离的天然方案,但当仓库内容出现关联时,没有任何一种调试方式比源码放在一起更高效。

多仓库的缺点:

  1. 管理、调试困难:多个 git 仓库管理起来是麻烦的,每次开发都需要打开多个仓库页面;对于共用的包通过 Npm 安装,如果不能接受调试编译后的代码,或每次 npm link 一下,就没有办法调试依赖的子包。

  2. 依赖关系复杂:独立仓库间组件版本号的维护需要手动操作,因为源代码不在一起,所以没有办法整体分析依赖,自动化管理版本号的依赖。

  3. 分支管理混乱:假如一个仓库A,同时供仓库B、C使用,当B项目优先开发了A,但A不兼容项目C,这就需要仓库A开两条分支同时供B、C使用,当仓库依赖复杂时,分支管理的成本将会显著提高。

  4. 占用空间大:每个仓库git data拥有大量分支数据,一旦仓库变多,整体git data将会变大,再加上各自的node_modules,这些仓库将占用大量空间。

4、monorepo的优势

  • 可见性:每个人都可以看到其他人的代码,这样可以带来更好的协作和跨团队贡献——不同团队的开发人员都可以修复代码中的 bug,而你甚至都不知道这个 bug 的存在。

  • 依赖管理成本降低:由于项目之间的引用路径内化在同一个仓库之中,我们很容易追踪当某个项目的代码修改后,会影响到其他哪些项目。通过使用一些工具,我们将很容易地做到版本依赖管理和版本号自动升级。

  • 代码重用将变得非常容易:所有的项目代码都集中于一个代码仓库,我们将很容易抽离出各个项目共用的业务组件或工具。

  • 一致性:当你把所有代码库放在一个地方时,执行代码质量标准和统一的风格会更容易。

  • 共享时间线:API 或共享库的变更会立即被暴露出来,迫使不同团队提前沟通合作,每个人都得努力跟上变化。

  • 原子提交:原子提交使大规模重构更容易,开发人员可以在一次提交中更新多个包或项目。

  • 统一的 CI/CD:可以为代码库中的每个项目使用相同的 CI/CD部署流程。

  • 统一的构建流程:代码库中的每个应用程序可以共享一致的构建流程。

5、monorepo的劣势

  • 新人学习成本增高:如果代码库包含了许多紧密耦合的项目,那么新成员的学习曲线会更陡峭。如果没有完善的开发工具,在monorepo仓库中进行开发将会寸步难行。
  • 性能可能变差:随着迭代仓库会变大,IDE可能卡顿,甚至会影响构建、CI时间。
  • 成倍的commit提交记录:如果仓库涵盖较多子包,对这些子包同时开发会提交大量的commit信息。
  • 阻塞code review:GitHub、Gitlab、Code会对带有大量文件变更的pr进行文件展示限制。