1. 为什么我需要Monorepo
业务中有许多独立的项目,通常我们会把一些组件或utils工具方法封装成NPM包进行发布,然后在各个项目中引入使用。然而时间长了会发现这样做是有弊端的。比如A项目依赖了ComponentA,B项目也依赖了ComponentA。有一天我把ComponentA的Bug进行了修复,却需要同时升级AB两个项目的依赖。这样对于维护者是十分不友好的,因为维护者永远都不会知道,ComponentA这个组件到底还被什么项目给引用了,造成维护上的困难。
2. Monorepo vs Polyrepo
来自 monorepo.tools 的一张图,简洁明了的告诉你区别所在。建议先去过一下概念,然后再开始动手也不迟。
3. 项目搭建
我们使用 npm create vue@3命令来创建两个vue项目,分别命名为 app-business 和 app-customer,这两个端分别代表了我们业务中的B端业务和C端业务。接着我们用同样的命令,创建一个app-components 项目,代表了我们公共的组件库(注意在创建的时候,不需要勾选router和pinia)。
接着我们在 app-components 项目中做出以下修改:
- 修改 package.json 文件
- 接着我们稍微修改下components目录和main.ts目录,如图所示
(当然了,要完整的搭建组件库没那么简单,这里只是为了做一个简单的演示)
4. Monorepo技术方案选型
这里我选用了微软的Rush框架进行管理,文档点此进行跳转,优点我就不多说了,文档比我讲的还激动,别问,问就是好。
接着我们执行 npm install -g @microsoft/rush ,安装一下Rush框架,然后开整。
5. 已有项目转为Rush管理
在上面,我们实际上创建了三个项目,接着我们需要把这三个项目转到Rush中进行管理。
1. 首先,我们先创建一个空的文件夹,然后进行Rush初始化,并创建apps目录和libs目录,将来用于存放项目和组件库。
mkdir my-monorepo
cd my-monorepo
mkdir apps
mkdir libs
rush init
此时我们的目录结构应该是这样的
2. 接着我们把刚才创建的几个项目都迁移到 my-monorepo 的对应目录中
cp -r app-business my-monorepo/apps/app-business
cp -r app-customer my-monorepo/apps/app-customer
cp -r app-components my-monorepo/libs/app-components
完成之后我们的目录应该是这样的
3. 编辑 rush.json 文件,在projects字段中添加对应的对象
"projects": [
{
"packageName": "app-business",
"projectFolder": "apps/app-business"
},
{
"packageName": "app-customer",
"projectFolder": "apps/app-customer"
},
{
"packageName": "app-components",
"projectFolder": "libs/app-components"
}
]
4. 安装所有项目的依赖
我们在 my-monorepo 项目中的任意位置,使用 rush update 命令来安装我们所有项目的依赖。命令执行完后,我们可以看到所有项目下都生成了node_modules文件夹。这里需要注意一点,rush默认是通过pnpm进行安装的,如需要调整,需要指定npmVersion或者是yarnVersion,详见Rush文档。
5. 项目构建
使用 rush build 命令来构建我们的项目,Rush 会寻找项目内的 package.json 文件内 "scripts" 字段下的 "build" 指令。比如我们的vue3项目,Rush会执行下图的命令。
需要注意的是:
- 事实上官方是不推荐我们一口气将所有的项目进行迁移的,他更推荐我们一个个进行迁移,因为这种逐步推进的方式更容易排查错误,也能让git历史变得更清晰。
rush build默认会对所有的项目进行构建,如果只想选择某个项目进行构建的话,可以加上对应的to参数,比如rush build --to app-business就表示只构建构建app-business和app-business依赖的所有项目。
6. 添加组件库依赖并引入
在上面我们已经在项目转到Rush中进行管理,接着我们分别为 app-business 和 app-customer 安装 app-components 依赖,具体操作如下:
cd apps/app-business
rush add -p app-components
cd apps/app-customer
rush add -p app-components
在Rush中,我们不会用到pnpm i / npm i / yarn add 的方式去添加依赖,而是通过rush add的方式去添加对应的依赖。默认通过 rush add -p 的方式依赖会被添加到 dependencies中,如果需要将依赖添加到 devDependencies中,则需要加上--dev参数。
接下来我们在 app-business 和 app-customer 项目中的App.vue文件引入对应的组件并使用,如图所示:
这样,当我们修改Button组件中的内容,其他引入该组件的项目也会同步进行更新了。
7. 检测不同项目中的依赖版本
在实际的开发场景中,可能会存在不同的项目引入的依赖是相同的,但是版本号不同。在大多数情况下,我们不需要进行修改,但如果该依赖是刚修复了一个重大的安全漏洞呢?我们就不得不将其进行升级。这个时候我们可以使用rush check命令来检测仓库内所有的依赖是否都有相同的版本。
比如我在 app-business,app-customer, app-components中分别安装了不同的dayjs版本,如图所示:
运行rush check命令后如图所示:
这个时候如果我们想把不同项目下的dayjs统一升级到最新的版本,我们可以使用rush upgrade-interactive --make-consistent命令,选择dayjs进行升级,如图所示
按回车后,所有的依赖都升级到最新的1.11.7的版本了。
8.同时运行多个项目
在实际的需求中,我们可能有一个SSO项目,加上其他几个子系统,那么肯定希望能在同一时间运行多个项目,这个时候我们可以使用Rush社区中的一个库:rush-select 来同时运行我们的项目。首先进行全局安装:npm install @telia/rush-select -g,接着我们在Rush项目中运行 rush-select 命令,如图所示:
先用左右箭头选中对应的模式,最后按Enter运行,比如我这里就选择了 app-business和app-customer这两个项目运行,结果如图所示: