Lerna初探 | ¥ЯႭ1I0
source link: https://yrq110.me/post/tool/study-on-lerna/?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Lerna初探
2018年12月27日
lerna是一个用于管理包含多个package结构的代码仓库的工具,优化工作流。新版的vue-cli、nuxt与babel均使用lerna进行自身的package管理。
package可理解为功能模块或子项目。
本文使用的lerna版本: version 3.8.0
- 当存在一个含有多个package的monorepo
- 管理这些package的版本与发布时
- 管理package共用的代码规范等配置时
- 管理package共用的依赖时
lerna的主要功能可以分为:版本控制
与发布
,需要与npm(或yarn)和git一同使用。
-
fixed/locked(默认)
固定模式。该模式为单版本号,在根目录中的
lerna.json
中设置。当使用lerna publish
时,如果自从上次发布后有模块改动,那么将会更新到新发布的版本。这也是目前Babel用的模式,当你想要自动整合不同包的版本时使用这个模式。它的特点是任何package的major change均会导致所有包都会进行major version的更新。
-
independent
lerna init --independent
独立模式。该模式中允许开发者独立管理多个包的版本更新。每次发布时,会得到针对每个包改动(patch, minor, major custom change)的提示。lerna会配合git,检查文件变动,只发布有改动的package。
独立模式允许开发者更新指定package的版本。将
lerna.json
中的version
键设为independent
来启用独立模式。
在项目根目录的lerna.json
中设置lerna的相关配置。
{
"version": "1.0.0",
"npmClient": "yarn",
"command": {
"publish": {
"ignoreChanges": ["ignored-file", "*.md"]
}
},
"packages": [
"packages/*"
]
}
常用的字段:
key | value |
---|---|
version |
当前仓库版本,当设为independent 时开启独立模式 |
npmClient |
执行命令的client,默认为npm ,可以设为yarn |
command.publish.ignoreChanges |
设置不会包含进lerna change/publish 操作的文件路径,使用它来避免一些非重要改动时的版本更新,比如更新README.md 中的拼写错误 |
packages |
用于定位package的文件路径 |
yarn workspace
lerna与yarn的workspace
特性很好的融合在了一起,前者负责版本管理与发布
,后者负责依赖管理
。
workspace
的特点:在所有workspaces所匹配的项目路径下会执行统一的yarn命令,包含测试、安装依赖或执行脚本。
在lerna中启用workspace:
lerna.json
中lerna的设置
{
...
"npmClient": "yarn",
"useWorkspaces": true,
...
}
lerna与yarn workspace
有很好的相性,设置useWorkspaces
等价于使用bootstrap
命令的--use-workspaces
选项,详情见bootstrap
根目录下的package.json
{
...
"private": true,
"workspaces": [
"packages/*"
],
...
}
"private": true
是必须的,workspaces
为工作空间中所包含的项目路径,详见workspace
需要注意的是,若开启了workspace功能,则lerna会将package.json
中workspaces
中所设置的项目路径作为lerna packages
的路径,而不会使用lerna.json
中的packages
值。相关源码:
get packageConfigs() {
if (this.config.useWorkspaces) {
const workspaces = this.manifest.get("workspaces");
...
return workspaces.packages || workspaces;
}
return this.config.packages || [Project.PACKAGE_GLOB];
}
也就是说,如果使用workspace
时未开启useWorkspaces
,则yarn
与lerna
会分别管理对应的项目路径。
以vue-cli为例,它的lerna.json
配置:
{
"npmClient": "yarn",
"useWorkspaces": false,
"version": "3.2.1",
"packages": [
"packages/@vue/babel-preset-app",
"packages/@vue/cli*"
]
}
根目录下的package.json
:
{
"private": true,
"workspaces": [
"packages/@vue/*",
"packages/test/*",
"packages/vue-cli-version-marker"
],
...
}
它将useWorkspaces
设为了false,那么意味着使用yarn
管理的是package.json
中workspaces
所对应的项目路径下的依赖,有@vue
下的所有项目,test
中的测试文件和vue-cli-version-marker
。而leran
管理的是lerna.json
中packages
所对应的@vue/babel-preset-app
和@vue/cli*
的版本与发布。
而在nuxt
中则是lerna
与yarn workspace
均采用了相同的package路径。
依赖管理与npm script
下面所操作的lerna
项目默认开启了useWorkspaces
安装lerna与初始化lerna项目
```shell
yarn global add lerna
mkdir monorepo && cd monorepo
lerna init
```
创建package
```shell
cd packages
mkdir module-a && cd module-a
yarn init
```
将package的`name`设置成统一的`@repo/module`的格式,在这里就是`@monorepo/module-a`
依赖的安装与移除
添加所有package中的依赖
lerna add dep-name
会将dep-name
包安装到packages所包含的package中。
移除所有package中的依赖
lerna exec -- yarn remove dep-name
移除packages所包含的package中的dep-name
包。
给指定package中添加依赖
lerna add dep-name --scope module-a
在module-a
package中添加的dep-name
包,使用--scope
命令限定目标package范围。
移除指定package中的依赖
lerna目前并没有remove
这种命令,需要在对应package的package.json
中删除对应依赖,然后执行lerna bootstrap
即可。
在package中引入相邻依赖
目前的项目结构如下:
monorepo/
packages/
module-a/
module-b/
如果想在module-b
中引入module-a
,执行如下命令即可
lerna add @monorepo/module-a --scope @monorepo/module-b
执行npm script
执行所有package中的scripts
命令
使用lerna的run
命令就可以在每个package中执行所包含的对应脚本,前提是需要先在package中写好公共的scripts
。
比如,若每个package均有test
script
"name": "@monorepo/module-a",
"scripts": {
"test": "jest"
}
则使用如下命令即可在每个package内执行测试:
lerna run test --stream
执行指定package中的scripts命令
需要使用--scope
过滤器来限定作用范围
比如,在project-alpha的package.json
中:
{
"name": "project-alpha",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"dev": "node index.js"
}
}
运行它的dev
命令需用下面的语句:
lerna exec --scope project-alpha -- yarn run dev
采用统一的规范配置
以husky和prettier为例
yarn add --dev husky prettier lint-staged -W
使用-W
选项会将依赖安装到workspace
的根目录下。
在根目录下正常设置相关配置文件
// .prettierrc
{
"singleQuote": true,
"jsxBracketSameLine": true,
"bracketSpacing": true,
"semi": true,
"arrowParens": "always",
"printWidth": 120
}
// package.json
{
...
"scripts": {
...
"precommit": "lint-staged",
...
},
"lint-staged": {
"packages/**/*.{js,jsx}": [
"prettier --write",
"git add"
]
},
...
"devDependencies": {
"husky": "^1.2.1",
"lerna": "^3.8.0",
"lint-staged": "^8.1.0",
"prettier": "^1.15.3"
}
}
git commit -m "lint test"
这样,每次在根目录下执行git命令时会对里面的所有package进行lint
共用的devDependencies
多数package中共用的devDependencies
类型的库都可以提升到项目根目录中,这样做的好处有:
- 所有包使用相同版本的依赖,统一管理
- 可使用自动化工具让根目录下的依赖保持更新
- 减少依赖的安装时间,一次安装,多处使用
- 节省存储空间,安装在根目录的
node_module
下
提交与发布
与lerna
中版本控制及发布相关的概念与工具:
-
约定式提交
。一种源于AngularJS commit rules的提交规则。 -
用于从git元数据中生成
CHANGELOG.md
的工具,该工具仅当遵循Conventional Commits
规则时起作用。 -
lerna
中内置的一个工具,用于生成版本号、git标签、Conventional Changelog、发布的提交信息以及修改记录。可以在lerna.json
中将conventionalCommits
标记设为true
开启,该工具仅当遵循Conventional Commits
规则时起作用。 -
一个遵循
Conventional Commits
的commit信息格式化工具
具体的操作与demo可查看这篇文章
command | value | options |
---|---|---|
lerna init |
创建一个新的lerna项目或将已存在项目改造为lerna项目 | --independent /-i |
lerna bootstrap |
当使用yarn 并开启了workspace 时等价于在根目录执行yarn install |
|
lerna import <pathToRepo> |
将本地路径<pathToRepo> 中的包导入到packages/<directory-name> ,并提交操作记录 |
|
lerna publish |
对更新后的包发布新版本;使用新版本号标记;升级所有npm和git中的库 | --npm-tag [tagname] , --canary/-c , --skip-git , --force-publish [packages] |
lerna change |
检查自上次发布以来改动的包 | |
lerna diff [package?] |
比较自上次发布以来的所有或指定的包 | |
lerna run [script] |
在每个包中执行一个npm script | |
lerna ls |
列出当前lerna项目中的public包 |
用来过滤命令执行时的范围,详见@lerna/filter-options
filter | description |
---|---|
--scope <glob> |
仅包含glob所匹配到的package |
--ignore <glob> |
排除glob匹配到的package |
--no-private |
排除私有package,默认是包含的 |
注意,如果package想要使用npm script执行本地的可执行文件需要自己单独设置依赖。并且,在package的package.json
中,一般还需设置在runtime需要的依赖和一些公共的scripts
- 跨项目本地开发
- TypeScript项目
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK