lerna
Lerna 是一个用来优化托管在 Git/NPM 上的多 package 代码库的工作流的一个管理工具,可以让你在主项目下管理多个子项目,从而解决了多个包互相依赖,且发布时需要手动维护多个包的问题。
解决场景
// module-1 package.json
{
"name": "module-1",
"version": "1.0.0",
"dependencies": {
"module-2": "^1.0.1"
}
}
// module-2 package.json
{
"name": "module-2",
"version": "1.0.1",
"dependencies": {}
}
如上所示,module-1依赖于module-2的。当module-2修改后,需要做如下操作:
- 修改module-2版本号,发布。
- 修改module-1的依赖关系,修改module-1的版本号,发布。
如何使用lerna
安装
yarn global add lerna
初始化文件结构
// 配置文件
- packages(目录)
- lerna.json(配置文件)
- package.json(工程描述文件)
// 文件结构
--packages
--module-1
package.json
--module-2
package.json
--lerna.json
--package.json
lerna.json
{
"version": "1.0.0",
"npmClient": "yarn",
"command": {
"publish": {
"ignoreChanges": ["ignored-file", "*.md"]
},
"version": {
"conventionalCommits": true
}
},
"packages": [
"packages/*"
],
"ignoreChanges": [
"**/*.md"
]
}
- version: 当前仓库版本,当设为independent时开启独立模式
- npmClient: 执行命令的client,默认为npm,可以设为yarn
- command:指令预设
- command.bootstrap: 对bootstrap指令预设。如设置hoist属性为true可以把所有模块的依赖包提升到根目录。
- command.publish.ignoreChanges: 设置不会包含进lerna change/publish操作的文件路径,使用它来避免一些非重要改动时的版本更新,比如更新README.md中的拼写错误。
- version:对lerna version(包含publish过程)进程设置。
- conventionalCommits:生成CHANGELOG
- packages:用于定位package的文件路径
- useWorkspaces: 在所有workspaces所匹配的项目路径下会执行统一的yarn命令,包含测试、安装依赖或执行脚本。默认为false。同时依赖包会提升到根目录,子包会依赖根目录到模块。
- ignoreChanges:忽略某些文件的变动。
工作模式
Fixed/Locked mode (default)
在publish的时候,会在lerna.json文件里面"version": "0.1.5",依据这个号,进行增加,只选择一次,其他有改动的包自动更新版本号。
Independent mode
每次publish时,您都将得到一个提示符,提示每个已更改的包,以指定是补丁、次要更改、主要更改还是自定义更改。
命令
创建或者改造为lerna项目
lerna init
创建一个包
lerna create package-a
// 创建一个b,放在package-b目录下面(package-b需要先在根目录的workspaces中指定)
lerna create b pakcage-b
添加所有package中的依赖
lerna add dep-name
// 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 in all modules except module-1
lerna add module-1
// Install babel-core in all modules
lerna add babel-core
列出所有的包
lerna list
导入本地已经存在的包
lerna import /xxx/xxx/xx
移除所有package中的依赖
lerna exec -- yarn remove dep-name
给指定package中添加依赖
lerna add dep-name --scope module-a
移除指定package中的依赖
lerna目前并没有remove这种命令,需要在对应package的package.json中删除对应依赖,然后执行lerna bootstrap即可。
在package-a中引入package-b
lerna add package-a --scope package-b
执行所有package中的script命令
// 指定test指令
lerna run test --stream
运行任意命令在每个包
lerna exec -- < command > [..args] # runs the command in all packages
lerna exec -- rm -rf ./node_modules
lerna exec -- protractor conf.js
lerna exec --scope my-component -- ls -la
执行指定package中的script命令
lerna exec --scope package-a -- yarn run dev
项目包建立软链
lerna link
删除所有包的node_modules目录
lerna clean
列出下次发版lerna publish 要更新的包
lerna changed
- 需要先git add,git commit 提交。
- 然后内部会运行git diff --name-only v版本号,搜集改动的包,就是下次要发布的
发布
对更新后的包发布新版本;使用新版本号标记;升级所有npm和git中的库
lerna publish [--npm-tag [tagname], --canary/-c, --skip-git, --force-publish [packages]]
// 发布alpha测试版本
lerna publish --pre-dist-tag alpha prerelease
// 强制升级发包
lerna publish --force-publish
// 发布正式patch版本
lerna publish --force-publish --pre-dist-tag latest patch
如果包名是带scope的,如name: @vue/cli,需要在该包的package.json下指定:
"publishConfig": {
"access": "public"
}
lerna publish过程:
- 调用lerna version
- 找出从上一个版本发布以来有过变更的 package
- 提示开发者确定要发布的版本号
- 将所有更新过的的 package 中的package.json的version字段更新
- 将依赖更新过的 package 的 包中的依赖版本号更新
- 更新 lerna.json 中的 version 字段
- 提交上述修改,并打一个 tag
- 推送到 git 仓库
- 使用 npm publish 将新版本推送到 npm
设置指定版本
lerna version 1.0.1 # 明确的
lerna version patch # semver 关键字
lerna version # 从提示中选择
lerna version [major | minor | patch | premajor | preminor | prepatch | prerelease]
# 使用下一个语义版本值,这将跳过“为…”选择新版本的提示
其它指令
- lerna bootstrap[--independent/-i]: lerna bootstrap,install+模块软链
- lerna import : 将本地路径中的包导入到packages/,并提交操作记录
其它配套的依赖
- commitizen:格式化提交格式。
- cz-lerna-changelog:lerna定制的提交规范。package添加如下配置:
{
"name": "root",
"private": true,
"scripts": {
"c": "git-cz"
},
"config": {
"commitizen": {
"path": "./node_modules/cz-lerna-changelog"
}
},
"devDependencies": {
"commitizen": "^3.1.1",
"cz-lerna-changelog": "^2.0.2",
"lerna": "^3.15.0"
}
}
- husky:拦截继承git hook,自定义钩子脚本
一些约定
采用 Monorepo 结构的项目,各个 package 的结构最好保持统一
- package 入口统一为 index.js
- 各 package 源码入口统一为 src/index.js
- 各 package 编译入口统一为 dist/index.js
- 各 package 统一使用 ES6 语法、使用 Babel 编译、压缩并输出到 dist
- 各 package 发布时只发布 dist 目录,不发布 src 目录
- 各 package 注入 LOCAL_DEBUG 环境变量, 在index.js 中区分是调试还是发布环境,调试环境 ruquire(./src/index.js) 保证所有源码可调试。发布环境 ruquire(./dist/index.js) 保证所有源码不被发布。