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的项目,并进行脚本运行,包的装置和依靠,版别操控和发布。

剩下的交给你们。