- 关于lerna
- 命令介绍
- Adds the module-1 package to the packages in the ‘prefix-‘ prefixed folderslerna add module-1 packages/prefix-* # Install module-1 to module-2lerna add module-1 —scope=module-2 # Install module-1 to module-2 in devDependencieslerna add module-1 —scope=module-2 —dev # Install module-1 in all modules except module-1lerna add module-1 # Install babel-core in all moduleslerna add babel-core
- DEMO
- 参考:
关于lerna
Lerna 是一个用git和npm来优化这个管理多包库工作流的工具。用于管理具有多个包的JavaScript项目的工具。 这个介绍可以说很清晰了,引入lerna后,上面提到的问题不仅迎刃而解,更为开发人员提供了一种管理多packages javascript项目的方式。 1. 自动解决packages之间的依赖关系。 2. 通过git 检测文件改动,自动发布。 3. 根据git 提交记录,自动生成CHANGELOG
命令介绍
api | 作用 |
---|---|
lerna bootstrap | 安装依赖 |
lerna clean | 删除各个包下的node_modules |
lerna init | 创建新的lerna库 |
lerna list | 显示package列表 |
lerna changed | 显示自上次relase tag以来有修改的包, 选项通 list |
lerna diff | 显示自上次relase tag以来有修改的包的差异, 执行 git diff |
lerna exec | 在每个包目录下执行任意命令 |
lerna run | 执行每个包package.json中的脚本命令 |
lerna add | 添加一个包的版本为各个包的依赖 |
lerna import | 引入package |
lerna link | 链接互相引用的库 |
lerna create | 新建package |
lerna publish | 发布 |
可以使用 lerna [command] -h
查找单个命令的使用方法和参数.
1、lerna bootstrap
执行该命令会做下面四件事情:
(1)、为每个包安装依赖
(2)、.链接相互依赖的库到具体的目录
(3)、.执行 npm run prepublish
(4)、执行 npm run prepare
默认是npm i,因为我们指定过yarn,so,run yarn install,会把所有包的依赖安装到根node_modules.
– —production —no-optional | 指定npm client的参数 |
–hoist | 把依赖安装到根目录的node_modules |
–ignore | 忽略的包 —ignore test-* 忽略名称以test开头的包 |
–scope | 指定的包 参数的含义是指包的名称 |
–ignore-scripts | 不执行声明周期脚本命令, 比如 prepare |
–registry | 指定registry |
–npm-client | 指定安装用的npm client lerna bootstrap —npm-client=yarn |
–use-workspace | 使用yarn workspace, 没用过 |
–no-ci | 默认调用 npm ci 替换 npm install , 使用选项修改设置 npm ci 类似于 npm-install ,但它旨在用于自动化环境,如测试平台,持续集成和部署。 |
–skip-git | 将不会创建git commit或tag |
–skip-npm | 将不会把包publish到npm上 |
–canary | 可以用来独立发布每个commit,不打tag lerna publish —canary |
2、lerna list 列举当前lerna 库包含的包
列出所有的包,如果与你文夹里面的不符,进入那个包运行yarn init -y解决
–json | 显示为json格式 |
–all | 显示包含private的包 |
–long | 显示更多的扩展信息 |
3、lerna changed
列出下次发版lerna publish 要更新的包。选项通 list
原理:
需要先git add,git commit 提交。
然后内部会运行git diff —name-only v版本号 ,搜集改动的包,就是下次要发布的。并不是网上人说的所有包都是同一个版全发布。
➜ lerna-repo git:(master) ✗ lerna changed info cli using local version of lernalerna notice cli v3.14.1lerna info Looking for changed packages since v0.1.4daybyday #只改过这一个 那下次publish将只上传这一个lerna success found 1 package ready to publish
4、lerna diff
显示自上次relase tag以来有修改的包的差异, 执行 git diff
5、lerna exec
在每个包目录下执行任意命令
–concurrency | 默认命令时并行执行的, 我们可以设置并发量为1(全局参数) | lerna exec —concurrency 1 – ls -la |
–scope | 设置包含的package | lerna exec —scope my-component – ls -la |
–stream | 交叉并行输出结果 | lerna exec —stream – babel src -d lib |
–parallel | Execute command with unlimited concurrency, streaming prefixed output.指为项目的中需要一直的进程,打印所有子进程的输出。说得有点绕,理解为需要一直运行的就加上这个参数就可以了。 | |
–no-bail | Continue executing command despite non-zero exit in a given |
$ lerna exec — < command > [..args] # runs the command in all packages$ lerna exec — rm -rf ./node_modules$ lerna exec — protractor conf.jslerna exec —scope my-component — ls -la
6、lerna run 选项同lerna exec
执行每个包package.json中的脚本命令
lerna run < script > — [..args] # 运行所有包里面的有这个script的命令$ lerna run —scope my-component test
7、lerna init
创建一个新的lerna库或者是更新lerna版本
默认lerna有两种管理模式, 固定模式和独立模式
固定模式 —exact
固定模式,通过lerna.json的版本进行版本管理。当你执行lerna publish命令时, 如果距离上次发布只修改了一个模块,将会更新对应模块的版本到新的版本号,然后你可以只发布修改的库。
在publish的时候,会在lerna.json文件里面”version”: “0.1.5”,,依据这个号,进行增加,只选择一次,其他有改动的包自动更新版本号。
这种模式也是Babel使用的方式。如果你希望所有的版本一起变更, 可以更新minor版本号,这样会导致所有的模块都更新版本。
独立模式 —independent
独立模式,init的时候需要设置选项 —independent. 独立模式允许管理者对每个库单独改变版本号,每次发布的时候,你需要为每个改动的库指定版本号。这种情况下, lerna.json的版本号不会变化了, 默认为independent。
lerna.json文件里面”version”: “independent”,每次publish时,您都将得到一个提示符,提示每个已更改的包,以指定是补丁、次要更改、主要更改还是自定义更改。
8、lerna clean
9、lerna import
导入指定git仓库的包作为lerna管理的包
–flatten | 如果有merge冲突, 用户可以使用这个选项所谓单独的commit | lerna import ~/Product —flatten |
–dest | 可以指定导入的目录(lerna.json中设定的目录) | lerna import ~/Product —dest=utilities |
10、lerna add [@version] [—dev] [—exact]
增加本地或者远程 package做为当前项目 packages里面的依赖
- —dev devDependencies 替代 dependencies
- —exact 安装准确版本,就是安装的包版本前面不带^, Eg: “^2.20.0” ➜ “2.20.0”
```bash
Adds the module-1 package to the packages in the ‘prefix-‘ prefixed folderslerna add module-1 packages/prefix-* # Install module-1 to module-2lerna add module-1 —scope=module-2 # Install module-1 to module-2 in devDependencieslerna add module-1 —scope=module-2 —dev # Install module-1 in all modules except module-1lerna add module-1 # Install babel-core in all moduleslerna add babel-core
<a name="Y7e6w"></a>
### 11、lerna link
链接互相引用的库<br />链接依赖<br />有个强大的命令叫 `lerna link convert`,它可以将所有公共依赖提取到根目录并链接各个仓库。这样,可以确保所有仓库用的都是一个版本。<br />有种错误的链接方式是yarn workspace 一个lerna包 add 另一个lerna包@0.1.0,这种必须使用版本号安装,否则报错,如果用了lerna link convert,就不需要使用这种方式。
<a name="FGZmr"></a>
### 12、lerna create <name> [loc]
新建包 name包名,loc 位置可选
```bash
# 根目录的package.json
"workspaces": [
"packages/*",
"packages/@gp0320/*"
],
# 创建一个包gpnote默认放在 workspaces[0]所指位置
lerna create gpnote
# 创建一个包gpnote指定放在 packages/@gp0320文件夹下,注意必须在workspaces先写入packages/@gp0320,看上面
lerna create gpnote packages/@gp0320
13、lerna version
这个命令 识别出修改的包 —> 创建新的版本号 —> 修改package.json —> 提交修改 打上版本的tag —> 推送到git上。
—allow-branch
设置git上的哪些分支允许执行 lerna version 命令, 也可以在lerna.json中设置
{
"command": {
"publish": {
"allowBranch": "master"
}
}
}
多个
{
"command": {
"publish": {
"allowBranch": ["master", "feature/*"]
}
}
}
具体其他参数:lerna的基础使用
14、lerna publish
lerna publish 就是将 monorepo 需要发布的包,发布到 npm registry 上面去。
会打tag,上传git,上传npm。
分为几种不同的场景去运行:
lerna publish 永远不会发布 package.json 中 private 设置为 true 的包
lerna publish
# lerna version + lerna publish from-git
# 发布自上次发布来有更新的包(这里的上次发布也是基于上次执行lerna publish 而言)
lerna publish from-git
# 发布当前 commit 中打上 annoted tag version 的包(即 lerna publish from-git)
lerna publish from-packages
# 发布 package 中 package.json 上的 version 在 registry(高于 latest version)不存在的包
# 发布在最近 commit 中修改了 package.json 中的 version (且该 version 在 registry 中没有发布过)的包(即 lerna publish from-package)
- from-git 即根据 git commit 上的 annotaed tag 进行发包
- from-package 即根据 lerna 下的 package 里面的 pkg.json 的 version 变动来发包
- —canary 发测试版本的包
- 剩下不带参数的情况就直接走一个 bump version(即执行 lerna version)
configureProperties -> initialize -> execute
在 lerna 中,几乎所有子命令源码的执行顺序都是按照这样一个结构在进行,lerna 本身作为一个 monorepo,主要是使用 core 核心中的执行机制来去分发命令给各个子项目去执行
另外:如果你的包名是带scope的例如:”name”: “@gp0320/gpwebpack”,
那需要在packages.json添加
"publishConfig": {
"access": "public"
},
lerna publish
lerna info current version 0.1.4
#这句意思是查找从v0.1.4到现在改动过的包
lerna info Looking for changed packages since v0.1.4
? Select a new version (currently 0.1.4) Patch (0.1.5)
Changes:
- daybyday: 0.1.3 => 0.1.5 #只改动过一个
...
Successfully published:
- daybyday@0.1.5
lerna success published 1 package
发布过程
查找变更逻辑
从上面这个图可以看到其中会有一些坑:
坑1:分支3的情况,因为开发者自己打的一些标签会影响lerna查找变更,可能会造成一些变更的包没有发布
解决办法:
1. 尽量避免自己打Tag
2. 或者只在一个专门的分支上,例如master,专门运行lerna publish进行发布,这个分支不能自己打其他Tag
坑2:几条分支同时进行的情况,可能生成了相同的版本号,从而发生版本冲突
解决办法:
1. 分支开发者之间约定好各自版本号
2. 或者只在一个专门的分支上,例如master,专门运行lerna publish进行发布
坑3:运行lerna publish如果中途有包发布失败,再运行lerna publish的时候,因为Tag已经打上去了,所以不会再重新发布包到NPM
解决办法:
1. 运行lerna publish from-git,会把当前标签中涉及的NPM包再发布一次,PS:不会再更新package.json,只是执行npm publish
2. 运行lerna publish from-package,会把当前所有本地包中的package.json和远端NPM比对,如果是NPM上不存在的包版本,都执行一次npm publish
版本号的变更
分为independent模式和fix模式,上面第一张图其实是independent模式,就是每个包有自己的版本号,再附上一张fix模式的图,主要的差异部分用红色标出来了
其他问题
lerna3.x只支持npm,内部的可以用@ali/lerna,但是比较头疼的是如果packages里面既有要发外部的包,又有要发内部的包
目前的解法是将所有要发内部的包,package.json里面加上private:true,发布的步骤变成了:
1. 运行lerna version更新package.json和打Tag,这一步也会更新private:true的包
2. 运行lerna publish from-git,将刚刚更新的包发布到npm,这一步会忽略private:true的包
3. 写个自动化脚本,先把private:true的包改为private:false,代用tnpm publish发布,然后再把private改回来
DEMO
初始化项目
$ npm install lerna -g
$ mkdir lerna-gp && cd $_
$ npm lerna init # 用的默认的固定模式,vue babel等都是这个
# Add packages
$ cd packages
$ mkdir daybyday gpnode gpwebpack
...
#分别进入三个目录初始化成包
$ cd daybyday
$ npm init -y
$ cd ../gpnode
$ npm init -y
$ cd ../gpwebpack
$ npm init -y
完成后的目录结构:
➜ lerna-gp git:(master) ✗ tree
.
├── lerna.json
├── package.json
└── packages
├── daybyday
│ └── package.json
├── gpnode
│ └── package.json
└── gpwebpack
└── package.json
4 directories, 5 files
修改顶层 package.json & lerna.json 配置
# package.json 文件加入
"private": true,
"workspaces": [
"packages/*"
],
# lerna.json 文件加入
"useWorkspaces": true,
"npmClient": "yarn",
这样使得nodemodule会装在根目录并让所有包链接根目录node_modules。
参考:
- 官网:https://github.com/lerna/lerna
- 中文文档:https://github.com/minhuaF/blog/issues/2
- 深入 lerna 发包机制 —— lerna publish:https://zhuanlan.zhihu.com/p/362042945
- 使用lerna管理monorepo及发npm包实战教程:https://zhuanlan.zhihu.com/p/404166248