likes
comments
collection
share

使用lerna构建monorepo项目

作者站长头像
站长
· 阅读数 58

PS:lerna已经不维护了,声明在这里:github.com/lerna/lerna…

可以改用nx

使用lerna构建monorepo

monorepo是什么?

monorepo就是在一个git repository里面管理多个packages或者项目

在实际开发使用中,在哪些场景下可能你会想要使用这种代码管理的方式呢?

  • 你们团队是一个以全栈开发为目标的团队,可以将前后端的项目放在一个repository里面进行管理
  • 如果你是想使用微服务的,无论是后端微服务还是前端微服务(Single-SPA)之类的,你就可以在一个repository里面管理多个相关的项目。
  • 开源项目中对项目模块分开管理和发布,例如create-react-app

Lerna

monorepo是一种代码管理的概念,有很多工具都可以帮助你去实现,这里介绍的是Lerna

那么Lerna是什么呢?

官方解释是:

Lerna is a tool that optimizes the workflow around managing multi-package repositories with git and npm.

Lerna在提供了一些对多个package进行操作的命令之外,还提供了一些和对项目发布工作流程的一些支持。

我们这里使用的lerna v3。

初始化项目

要从一个新项目开始还是从已有项目出发,都可以使用lerna去创建monorepo的开发模式

lerna提供了两种方式去管理项目,一种是Fixed/Locked mode (default),另一种是Independent mode

区别就是,Fixed/Locked mode的版本控制是整一个repository作为一个整体的,而Independent mode则每个package的版本控制是独立的

我们这里介绍的是Independent mode的形式

执行下面命令对lerna进行初始化

npx lerna init --independent

会生成一个lerna.json的文件,这就是lerna的配置文件,内容如下

{
  "packages": [
    "packages/*"
  ],
  "version": "independent"
}

这里有两个配置,一个是packages,可以用来指定你需要管理的package的目录,默认配置是packages下面的第一级目录下的项目文件夹

如果要嵌套多层,可以改成

{
  "packages": [
    "packages/**"
  ]
}

如果需要添加其他目录,例如前后端一起的monorepo,可以修改为

{
  "packages": [
    "servers/*", "frontend/*"
  ]
}

具体的目录结构就视具体而定。

如果你是习惯使用yarn进行包管理的,我们还可以定义我们需要的包管理工具为yarn

{
  "version": "1.1.3",
  "npmClient": "npm",
  "packages": ["packages/*"]
}

具体的详细的lerna.json配置可以看lerna github上的Readme文档

执行package script

我们可以使用lerna run指令,去运行每个包中包含有相关package script的相关命令。

例如,我们有两个前端package,里面的package.json中都有一个start

{
	"srcipts": {
		"start": "react-scripts start",
	}
}

我们则可以直接运行

lerna run --parallel start

--parallel参数就是指为项目的中需要一直的进程,打印所有子进程的输出。说得有点绕,理解为需要一直运行的就加上这个参数就可以了。

包依赖

安装包

使用下面命令,可以安装所有包的package.json中的dependencies

npx lerna bootstrap

公共的包

我们可以将公共的包安装在根目录下的package.json下,例如,你是前端微服务的项目而且是使用react作为主要技术栈的,可以把reactreact-dom等安装在根目录下,packages都是可以直接引用的

更常用的是一些项目规范的配置,例如eslintprettiertsconfig之类的,也可以直接安装在根目录下

把公共包提取出来的好处有:

  • 所有包用的依赖包版本都是一致的
  • 做一些包的升级和像github进行包检查时,更方便地进行升级
  • 安装依赖包的时间可以更少
  • 需要更少的存储空间

项目中包与包之间的引用

如果我们packages里面需要进行互相引用

我们使用lerna add命令,可以为指定的包安装第三方的或者本地的包,这个指令和yarn add或者npm install实质上是类似的,下面是一些来自文档的一些例子

# Adds the module-1 package to the packages in the 'prefix-' prefixed folders
lerna add module-1 packages/prefix-*

# Install module-1 to module-2
lerna add module-1 --scope=module-2

# Install module-1 to module-2 in devDependencies
lerna add module-1 --scope=module-2 --dev

# Install module-1 to module-2 in peerDependencies
lerna add module-1 --scope=module-2 --peer

# Install module-1 in all modules except module-1
lerna add module-1

# Install babel-core in all modules
lerna add babel-core

版本控制

lerna的版本控制依赖于相应git branch上面的tag,来判断修改记录和进行相应的版本控制

这里一开始踩了坑,lerna是不支持git flow的,作者认为如果按照git flow的话,是一种anti-pattern,也就是反例。

相关的issue:github.com/lerna/lerna…

因为我们使用的是independent mode,所以我们需要对每个包的版本进行管理。如果项目使用了一些CI workflow的话,我们还需要将版本控制放到CI流程中去。

lerna进行版本控制的话,是使用lerna version命令。

具体做了几个事情:

  1. 定义了从上一个git branch release tag开始,哪些包被更新了
  2. 更新版本号
  3. 修改包的package.json里面的version, 运行在根目录下和每个更新包中的npm lifecycle scripts。提交这些修改,并打上release tag
  4. 推送到远程git repository

因此,lerna已经能为我们完成打release tag和更新changelog的工作。

最后,根据git flow,我们只需要将release分支合并回development分支,根据需要看是否需要hotfix release的代码,然后在合并到master/main分支,则完成了一次release

如果你需要有prerelease、beta的,也是类似的进行版本控制。lerna version提供了参数可以完成

  • --conventional-prerelease: 当前release是prerelease版本.
  • --conventional-graduate: 把prerelease版本的包变成稳定版本的包版本.

管理发布

最后,如果我们还需将包发布到npm或者其他registry上面,则需要用到lerna publish命令。

注意,如果你不是所有包都需要发布,可以在不需要发布的包中把package.jsonprivate设为true

publish命令有两种情况可选

# 发布在当前commit head下,被打了tag的包
lerna publish from-git     
# 发布在当前npm registry下,没有该版本的包
lerna publish from-package 

在publish的时候,有一个比较重要的参数--canary。 这个参数的意思是,在发布到npm之前,先在当前版本创建一个新版本,将minor版本加上1,还有加上alpha后缀,例如1.0.0会变成1.1.0-alpha)。如果需要指定后缀,则可以使用--preid参数进行定义,例如--preid beta

总结

至此,我们已经介绍了lerna如果创建一个简单的monorepo的项目,并进行脚本运行,包的安装和依赖,版本控制和发布。

剩下的交给你们。

转载自:https://juejin.cn/post/7085533287858307102
评论
请登录