乐趣区

关于monorepo:现代前端工程为什么越来越离不开-Monorepo

随着前端工程日益简单,某些业务或者工具库通常波及到很多个仓库,那么工夫一长,多个仓库开发弊病日益露出,由此呈现了一种新的项目管理形式——Monorepo。本文次要以 Monorepo 的概念、MultiRepo 的弊病、Monorepo 的收益以及 Monorepo 的落地这几个角度来意识和学习一下 Monorepo,文末会有思考题,欢送大家来踊跃探讨。

什么是 Monorepo?

Monorepo 其实不是一个新的概念,在软件工程畛域,它曾经有着十多年的历史了。概念上很好了解,就是把多个我的项目放在一个仓库外面,绝对立的是传统的 MultiRepo 模式,即每个我的项目对应一个独自的仓库来扩散治理。

古代的前端工程曾经越来越离不开 Monorepo 了,无论是业务代码还是工具库,越来越多的我的项目曾经采纳 Monorepo 的形式来进行开发。Google 宁愿把所有的代码都放在一个 Monorepo 工程上面,Vue 3YarnNpm7 等等出名开源我的项目的源码也是采纳 Monorepo 的形式来进行治理的。

个别 Monorepo 的目录如下所示,在 packages 寄存多个子项目,并且每个子项目都有本人的package.json:

├── packages
|   ├── pkg1
|   |   ├── package.json
|   ├── pkg2
|   |   ├── package.json
├── package.json
 

Monorepo 到底有什么魔力,让大家如此推崇,落地如此之广呢?

MultiRepo 之痛

要想晓得 Monorepo 的劣势,首先得弄清楚之前的开发方式有什么痛点。

之前传统的形式 MultiRepo 当中,每个我的项目都对应独自的一个代码仓库。我之前也是用这种形式开发的,是真真切切地感触到了这种形式带来的诸多弊病。当初就和大家一一分享一下。

代码复用

在保护多个我的项目的时候,有一些逻辑很有可能会被屡次用到,比方一些根底的组件、工具函数,或者一些配置,你可能会想: 要不把代码间接 copy 过去,多省事儿!但有个问题是,如果这些代码呈现 bug、或者须要做一些调整的时候,就得批改多份,保护老本越来越高。

那如何来解决这个问题呢?比拟好的形式是将公共的逻辑代码抽取进去,作为一个 npm 包进行公布,一旦须要改变,只须要改变一份代码,而后 publish 就行了。

但这真的就完满解决了么?我举个例子,比方你引入了 1.1.0 版本的 A 包,某个工具函数呈现问题了,你须要做这些事件:

  • 去批改一个工具函数的代码
  • 公布 1.1.1 版本的新包
  • 我的项目中装置新版本的 A

可能只是改了一行代码,须要走这么多流程。然而开发阶段是很难保障不出 bug 的,如果有个按钮须要改个款式,又须要把下面的流程从新走一遍 …… 停下来想想,这些反复的步骤真的是必须的吗?咱们只是想复用一下代码,为什么每次批改代码都这么简单?

上述的问题其实是 MultiRepo 普遍存在的问题,因为不同的仓库工作区的割裂,导致复用代码的老本很高,开发调试的流程繁琐,甚至在根底库频繁改变的状况下让人感到很抓狂,体验很差。

版本治理

MultiRepo 的开发方式下,依赖包的版本治理有时候是一个特地玄学的问题。比如说刚开始一个工具包版本是 v1.0.0,有诸多我的项目都依赖于这个工具包,但在某个时刻,这个工具包发了一个 break change 版本,和原来版本的 API 齐全不兼容。而事实上有些我的项目并没有降级这个依赖,导致一些莫名的报错。

当我的项目多了之后,很容易呈现这种依赖更新不及时的状况。这又是一个痛点。

我的项目基建

因为在 MultiRepo 当中,各个我的项目的工作流是割裂的,因而每个我的项目须要独自配置开发环境、配置 CI 流程、配置部署公布流程等等,甚至每个我的项目都有本人独自的一套脚手架工具。

其实,很容易发现这些我的项目里的很多基建的逻辑都是反复的,如果是 10 个我的项目,就须要保护 10 份基建的流程,逻辑反复不说,各个我的项目间存在构建、部署和公布的标准不能对立的状况,这样保护起来就更加麻烦了。

分支治理

MultiRepo 的开发方式下,如果组内每个迭代承接业务需要很多,波及到的工程可能多大五六个,有的业务需要走开发分支,有的业务需要走个性分支,有的需要在转测或者转演,有的要热修等等,这么多我的项目的分支治理特地简单,很容易呈现问题。

Monorepo 的收益

说分明 MultiRepo 的痛点之后,置信你也大略能了解为什么要诞生 Monorepo 这个技术了。当初就来粗疏地剖析一下 Monorepo 到底给古代的前端工程带来了哪些收益。

首先是工作流的一致性,因为所有的我的项目放在一个仓库当中,复用起来十分不便,如果有依赖的代码变动,那么用到这个依赖的我的项目当中会立马感知到。并且所有的我的项目都是应用最新的代码,不会产生其它我的项目版本更新不及时的状况。

其次是我的项目基建老本的升高,所有我的项目复用一套规范的工具和标准,无需切换开发环境,如果有新的我的项目接入,也能够间接复用已有的基建流程,比方 CI 流程、构建和公布流程。这样只须要很少的人来保护所有我的项目的基建,保护老本也大大减低。

再者,团队合作也更加容易,一方面大家都在一个仓库开发,可能不便地共享和复用代码,不便检索我的项目源码,另一方面,git commit 的历史记录也反对以性能为单位进行提交,之前对于某个性能的提交,须要改好几个仓库,提交多个 commit,当初只须要提交一次,简化了 commit 记录,不便合作。

Monorepo 的落地

如果你还素来没接触过 Monorepo 的开发,到这可能你会纳闷了: 刚刚说了这么多 Monorepo 的益处,可是我还是不晓得怎么用啊!是间接把所有的代码全副搬到一个仓库就能够了吗?

当然不是,在理论场景来落地 Monorepo,须要一套残缺的工程体系来进行撑持,因为基于 Monorepo 的项目管理,绝不是仅仅代码放到一起就能够的,还须要思考我的项目间依赖剖析、依赖装置、构建流程、测试流程、CI 及公布流程等诸多工程环节,同时还要思考我的项目规模达到肯定水平后的性能问题,比方我的项目构建 / 测试工夫过长须要进行增量构建 / 测试、按需执行 CI 等等,在实现全面工程化能力的同时,也须要兼顾到性能问题。

因而,要想从零开始定制一套欠缺的 Monorepo 的工程化工具,是一件难度很高的事件。不过社区曾经提供了一些比拟成熟的计划,咱们能够拿来进行定制,或者对于一些下层的计划间接拿来应用。

其中比拟底层的计划比方 lerna,封装了 Monorepo 中的依赖装置、脚本批量执行等等根本的性能,但没有一套构建、测试、部署的工具链,整体 Monorepo 性能比拟弱,但要用到业务我的项目当中,往往须要基于它进行顶层能力的封装,提供全面工程能力的撑持。

当然也有一些集成的 Monorepo 计划,比方 nx (官网写的真心不错,还有不少视频教程)、rushstack,提供从初始化、开发、构建、测试到部署的全流程能力,有一套比拟残缺的 Monorepo 基础设施,适宜间接拿来进行业务我的项目的开发。不过因为这些顶层计划外部各种流程和工具链都曾经十分欠缺了,如果要基于这些计划来定制,适配和保护的老本过高,根本是不可行的。

实例

我在搭建 React 业务组件库时应用了 lerna 治理多包存储库,独自发包,因为工程中只会应用某些业务组件,业务需要的变动只会改变某个业务组件,所以不能像通用组件库一样应用整体公布。

参考:从零到一搭建 react 业务组件库

总结

总而言之,Monorepo 的开发模式就是将各自独立的我的项目,变成一个对立的工程整体,解决 MultiRepo 下呈现的各种痛点,晋升研发效率和工程质量。那最初我还有有一个问题,采纳 Monorepo 解决了之前的痛点之后,产生了哪些新的问题呢?这些问题能够解决吗?欢送大家在留言区一起探讨。

参考资料

[1] lerna: https://lerna.js.org/

[2] nx: https://nx.dev/latest/react/g…

[3] rushstack: https://rushstack.io/

退出移动版