Monorepo简介与建设实践

5,638 阅读7分钟

Monorepo简介与建设实践

作者:重明

Monorepo和Multirepo对比

需要注意一点:monorepo和multirepo不是框架,不是库。 是一种管理项目的概念

monorepo

将所有的模块统一的放在一个主干分支之中管理。不进行分库存储,当有特定的需要的时候进行分支,但是问题修改还是在主干上操作,并有专门人员合并到分支内容上,在特定需求完结的时候,分支也将会被废弃。

优点:

1.统一的规范,语言,和IDE带来的是结构的完整稳定。

2.按照统一的标准进行开发,使程序稳定性更良好,更易解读。

3.标准化的开发流程,规避很多不必要的冲突与错误。

缺点:

1.项目过大,难以管理。

2.由于统一的标准,不同的团队可能需要对于新的规范和IDE进行了解学习,需要时间。

3.修改和开发可能变得繁琐,减慢效率。

multirepo

将项目分化成为多个模块,并针对每一个模块单独的开辟一个repo来进行管理。

优点:

1.团队自己的IDE,语言,以及工作步调。

2.模块更小,更易维护。

3.开发效率更高。

缺点:

1.合并困难,每个模块规范不同,同步和编译时这些问题将会集体爆发。

2.难以保证稳定性。

3.由于可能存在不同语言开发,或者不同IDE的情况,新建或者更新构建变得困难

大家看到multirepo是不是有点眼熟? 对了,这个就是微服务的概念。 大家多多少少对微服务都有所了解,这里就不展开了,往后可以单独分享

Lerna

Lerna是npm模块的管理工具,为项目提供了集中管理package的目录模式,如统一的 repo 依赖安装、package scripts和发版等特性。

想要初识monorepo上边这句话可能已经一脑袋问号了? 不要慌,我们翻译一下:

问:实现monorepo一共分几步?

答:一共分三步 ---

  1. --- 安装Lerna

  2. --- 使用Lerna (根据Lerna提供的结构放置项目)

  3. --- 提交项目

是不是明白了(╹▽╹)? 好! 那接下来咱们看一下Lerna是怎么使用的

安装Lerna

npm i -g lerna

好的,恭喜你完成了第一步!

使用Lerna

常用lerna命令

lerna init 创建一个新的lerna库或者是更新lerna版本

lerna add 添加一个包的版本为各个包的依赖

lerna create 新建包

lerna list 列举当前lerna 库包含的包

lerna changed 显示自上次relase tag以来有修改的包, 选项通 list

lerna diff 显示自上次relase tag以来有修改的包的差异, 执行 git diff

lerna clean 删除各个包下的node_modules

初始化项目

lerna init

初始化后,会生成 packages 空目录和 package.json 和 lerna.json 配置文件,配置文件如下:

image.png

//package.json
{
  "name": "root",
  "private": true, // 私有的,不会被发布,是管理整个项目,与要发布的npm包解耦
  "workspaces": ["packages/*"], // workspace配置
  "devDependencies": {
    "lerna": "^3.22.1"
  }
}

//lerna.json
{
  "packages": [
    "packages/*"
  ],
  "version": "0.0.0",
  "npmClient": "yarn", // workspace配置
  "useWorkspaces": true // workspace配置
}

这里有yarn workspace的命令混入其中,代码中已有标记。 它主要是为安装依赖的配置调整。 Lerna的一些操作较日常的操作而言有些蹩手,所以我们使用workspace来做能更加容易接受

创建npm包

执行命令后可修改包信息,这里创建@monorepo/feihe-project @monorepo/feihe-components 和 @monorepo/feihe-utils

image.png

lerna create @monorepo/feihe-project -y
lerna create @monorepo/feihe-components -y
lerna create @monorepo/feihe-utils -y

安装依赖

lerna add lodash // 为所有 package 增加 lodash 模块 

// 为 @monorepo/feihe-utils 增加 lodash 模块(lodash可替换为内部模块,如@monorepo/feihe-components)
lerna add lodash --scope @monorepo/feihe-utils 

当然也可以在各个package.json中的dependencies或devDependencies添加依赖,也可以使用yarn或npm在各包中进行安装,没有强行限制。比如从根目录到packages下所有包执行安装依赖, 执行yarn install即可

除此之外,我们可以将项目内的工具库@monorepo/feihe-utils导入至项目@monorepo/feihe-project中

lerna add @monorepo/feihe-utils --scope=@monorepo/feihe-project

image.png

在工具库中可直接导出es包, 安装依赖后直接使用

执行命令

当我们需要在根目录执行packages下的scripts命令时可以这样:

yarn workspace @monorepo/feihe-project run dev

当然也可以进入希望执行的目录下执行yarn run dev, 都没有问题

清理环境

在依赖乱掉或者工程混乱的情况下,清理依赖

lerna clean # 清理所有packages的node_modules目录,不能删除根目录的node_modules
yarn workspaces run clean # 执行所有package的clean操作(应是需自行写脚本)

注意: 以上两种清理的是packages的node_modules,不包含根目录,根目录需要自行删除。yarn workspaces run clean大家可能也看出来了,需要每个package中都在scripts中配置clean命令,所以是不是很坑...

提供一个解决方案:

在根目录的package.json中设置一下

// package.json
{
  "scripts": {
    "clean": "rimraf node_modules & lerna clean -y" // 清理所有依赖
  }
}

执行此命令需要安装rimraf包

npm install -g rimraf

提交项目

在构建和发布之前还需要做一些关于代码提交的配置

commitizen && cz-lerna-changelog

commitizen 是用来格式化 git commit message 的工具,它提供了一种问询式的方式去获取所需的提交信息。

cz-lerna-changelog 是专门为 Lerna 项目量身定制的提交规范,在问询的过程,会有类似影响哪些 package 的选择。

我们使用 commitizen 和 cz-lerna-changelog 来规范提交,为后面自动生成日志作好准备。 因为这是整个工程的开发依赖,所以在根目录安装:

yarn add commitizen cz-lerna-changelog -D -W

安装完成后,在 package.json 中增加 config 字段,把 cz-lerna-changelog 配置给 commitizen。同时因为commitizen不是全局安全的,所以需要添加 scripts 脚本来执行 git-cz

{
  "scripts": {
    "commit": "git-cz"
  },
  "config": {
    "commitizen": {
      "path": "./node_modules/cz-lerna-changelog"
    }
  }
}

之后在常规的开发中就可以使用 yarn run commit 来根据提示一步一步输入,来完成代码的提交。

commitlint && husky

上面我们使用了 commitizen 来规范提交,但很难靠开发自觉使用 yarn run commit 。万一忘记了,或者直接使用 git commit 提交怎么办?所以在提交时校验提交信息,如果不符合要求就不让提交,并提示。校验的工作由 commitlint 来完成,校验的时机则由 husky 来指定。husky 继承了 Git 下所有的钩子,在触发钩子的时候,husky 可以阻止不合法的 commit,push 等等。

安装 commitlint 以及要遵守的规范:

yarn add -D -W husky @commitlint/cli @commitlint/config-conventional

在工程根目录为 commitlint 增加配置文件 commitlint.config.js 为commitlint 指定相应的规范

module.exports = { 
    extends: ['@commitlint/config-conventional'] 
}

在 package.json 中增加如下配置

"husky": { 
    "hooks": { 
        "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 
    }
}

"commit-msg"是git提交时校验提交信息的钩子,当触发时便会使用 commitlint 来校验。安装配置完成后,想通过 git commit 或者其它第三方工具提交时,只要提交信息不符合规范就无法提交。从而约束开发者使用 yarn run commit 来提交。

流程简介

git add .

yarn run commit

image.png

image.png

image.png

git push origin xxxx(分支)

image.png

打包发布

我们可以自己构建拓扑排序规则,很不幸的是yarn的workspace暂时并未支持按照拓扑排序规则执行命令,虽然该 rfc已经被accepted,但是尚未实现, 幸运的是lerna支持按照拓扑排序规则执行命令, --sort参数可以控制以拓扑排序规则执行命令

lerna run --stream --sort build

OK! 收工! 欢迎大家持续关注我们,我们会保证至少周更1期前端内容,希望大家能提出宝贵建议,不要成为失联人口啊~


技术分享宣传图@3x.png