• 大厂都在用的多项目管理Monorepo方案是什么?
  • 发布于 2个月前
  • 95 热度
    0 评论
  • Scys
  • 5 粉丝 39 篇博客
  •   
背景介绍
在多个项目开发管理的过程中,大多都会有这样的一个困扰,我们在开发A项目的过程中,发现有个功能和B项目中的一个功能类似,简单修改一下就可以拿来用,同样在开发C项目的工程中,也会遇到和A项目中相似功能的场景,一般遇到这样的情况,我们可能就需要复制粘贴到当前项目中使用,这样看来,也没有什么太大的问题;但是,随着业务量越来越大,项目中相似的功能越来越多,我们每次渠去到不同的项目仓库中copy代码,就会显得影响开发效率,还有一个更大的问题是,后期维护的话,如果某个功能改动量很大,我们是不是需要在每个仓库中都去修改一遍。基于上面的情况,此次调研了Monorepo策略来实现多个项目的管理

多个项目存在的问题
1. 仓库多,管理混乱
.同一个小组的项目,被分成多个仓库,不利于管理
.新人上手难度大,需要熟悉多个仓库的代码目录
2.代码复用率低
.公共组件和方法,只能通过copy的形式或npm包的形式公用
.对每个仓库熟悉的情况下,会造成过多重复开发,影响迭代效率
3.开发规范不统一
.相同类型的项目,却有着不同代码风格校验规范(ESlint、prettier等 )

.每个项目使用不同的工具库,管理混乱


什么是Monorepo
Monorepo 全称 Monolithic Repository,Monorepo 是一种将多个项目代码存储在一个仓库里的软件开发策略,指单个仓库可包含许多相关但独立的项目,可以由同一个团队或多个团队管理。这使得跨项目共享和管理代码变得更加容易。

Monorepo 的优势
.仓库中的每个项目,都可分离出来运行;
.共享组件&方法更简单,只需引用根目录的组件或者方法即可;
.维护方便,每次只需要修改一个地方,子项目每次打包发布便会同步更新;

Monorepo策略整体架构,会先看到的是一个整体,然后在里面再分出各个端的内容,最后通过 webpack 打包多页面的方法,把各端自己的内容串起来,打包出各端的内容。

其他技术方案调研
1. npm包
我们一开始遇到代码复用的场景,最容易想到的就是将公共部分打包成一个npm包,放在私有npm仓库中,各个项目,npm install,然后直接拿来使用,npm包的形式,也算是一个办法,但相对来说,存在的一些缺点还是不能忽视的:
.随着项目体量增大,会需要更多的npm包,后期就需要维护更多的npm包

.一旦npm包有更新,就需要各个项目重新npm install, 才能使用到最新的功能


2. 微前端-Fusion前端融合组件
这种形式和npm包类似,针对不同的功能,需要维护多个仓库进行管理;另外Fusion前端融合组件,设计的初衷,是为了公司内部各个业务部门,对一些需要项目依赖的业务,而开发的一套融合方案,如果没有夸部门相互调用的场景,开发成本有点大,同样还需要后期维护;

Monorepo策略存在的缺点
仓库管理权限不可控:由于多个项目在一个仓库,就需要给所有开发者管理员权限;
新员工上手难度大:在 monorepo 策略下,新人可能不得不花更多精力来理清各个代码仓库之间的相互逻辑;

更新同步问题:由于每个项目的迭代周期不一致,如果公共组件或者方法有修改,一些项目迭代不及时,会导致落后的版本越来越多,对后期上线,造成不可估量的风险;


Monorepo策略实践
1.全局安装pnpm npm install -g pnpm
2.新建文件夹,然后在文件夹根目录执行 pnpm init, 初始化项目
3.创建 pnpm-workspace.yaml、.npmrc
pnpm-workspace.yaml是开启workspaces的配置文件 packages: - '**' 这个配置指示 pnpm 在名为packages的文件夹下查找所有的项目

.npmrc用来配置信息,engine-strict=true结合根目录的package.json中的engines字段,可以指定运行的node版和pnpm版本 engine-strict=true

配置根目录下的package.json文件,启用workspaces功能
"workspaces": {
    "packages": ["packages/*"]
}
创建子项目,放在新建的packages文件夹,并为每个pnpm init 每个子项目,生成package.json文件 packages projectA package.json projectB package.json

4.安装项目依赖
在项目根目录下运行 pnpm install,pnpm 将会自动识别workspaces,并在所有子项目中安装依赖项。此时根目录下会生成node_modules的文件夹。这个文件夹中的.pnpm子文件夹包含了所有已安装的包,而子项目的node_modules文件夹中包含了指向这些包的链接。

5.安装共享依赖项
多个项目放在一个仓库,我们通常希望能够共享一些依赖项,比如lodash、classes等,此时我们就可以在根目录中的package.json文件中,添加这些需要共享的依赖项:
"dependencies":{
    "lodash": "^4.17.21"
}
重新在根目录执行pnpm install 后,就可以在所有子项目中使用lodash, 而不需要在每个子项目的package.json文件中单独声明它。

6.项目脚本命令
使用pnpm 可以在根目录下运行子项目的脚本。例如:在projectA项目中的package.json中定义一个名为start的脚本
    "scripts": {
        "start": "node ./index.js"
    }
然后在根目录运行 pnpm --filter projectA run start 即可执行projectA的start脚本命令,后面可以配置打包命令

6.执行全局命令
如果配置了单元测试,只需要在根目录中的package.json文件中配置test命令,每次执行的时候,pnpm会将所有子项目中的test脚本都执行
    "scripts": {
        "test": "pnpm run test --filter ./packages/*"
    }
总结
Monorepo是一个很好的多项目管理策略,但针对当前团队项目的现状,不宜进行整合,原因如下:
拆分组件工作量:由于之前的多个项目是分布在多个仓库管理的,一些相似组件的调用,都是copy的形式,现在需要单独拆分出来,还需要考虑各个项目调用的差异,进行重新封装
业务逻辑接入工作量:完成了上面所说的公共组件或者方法的拆分,还需要每个项目再重新接入,有一定的工作量,而且涉及到的功能模块,都需要测试回归功能完好,才能重新上线;
仓库管理权限分配:项目合到一个仓库,仓库权限管理混乱,如果改动了公共逻辑,可能会造成其他项目,无法正常打包上线;
迭代周期问题:由于不同的项目,有不同的迭代发布日期,如果改了公共部分逻辑,A项目发布上线,对一些不常更新的项目,欠债越来越越多,导致风险不可预估;
用户评论