本文主要总结了本人在使用 lerna 进行多包管理中常用的一些命令详解,帮助刚刚接触 lerna 的朋友快速上手搭建可用的 lerna 仓库工作流。Enjoy it :)
About lerna
Lerna 是一个可以用来管理多个 JavaScript 项目 package 的工具。当项目中遇到将一个大项目仓库拆分成 monorepos,将这些 package 分散存放在独立的项目仓库之中,但是这会使得代码变更变得难以追踪,同时,由于多包之间存在复杂的依赖关系,这种也会使得包与包之间依赖管理变得混乱。而 Lerna 提供了一种新的思路,Lerna 是针对使用 git 和 npm 管理多包代码仓库的流程进行优化的工具 (Lerna is a tool that optimizes the workflow around managing multi-package repositories with git and npm.)
Init lerna
-
创建一个 git 仓库,并 clone 到本地,进入该 git 仓库目录
-
可以全局安装或者通过 npm 依赖安装 lerna,并执行
lerna init将仓库转为 lerna 仓库- attention: 如果执行
init时加上--independent参数,lerna 将会以独立版本控制的模式进行管理,即每个包将会是独立的版本号。
- attention: 如果执行
-
执行之后,该仓库目录变成了如下的结构
lerna-repo // 根目录的 package.json package.json // lerna 配置 lerna.json // npm包具体放置目录 packages/ package-1/ package.json package-2/ package.json
本人的 Workflow
我们项目会分为好几个版本进行部署测试,如 dev、test、pro。所有人开发的特性分支都需要合入到 dev 中,dev 验收通过之后,再合入至 test。 在 test 测试或者修复测试之后,再合入到 pro,这些主干分支都是单向流动 dev-> test-> pro-> dev 。只有在 dev、test 环境都验收之后,才会让 pro 的代码正式上岗,正式发布。
Lerna 日常使用命令
完成初始化 lerna 仓库之后,接下来就要开始进行 lerna 的管理工作。这里仅总结了日常部分 lerna 使用过程中常用的指令以及常用的指令参数。具体可以参阅 Lerna commands-github,这个目录下会详细介绍每个命令执行的内容,以及相关参数的使用。
lerna bootstrap
keyword: install & symlink
这个命令主要是用来执行 packages/ 目录下每个包的 npm install 命令,并将这些包直接的相互依赖关系进行链接。当执行这个命令时,这个命令会执行:
npm install安装所有包的外部依赖;- 将目录下有依赖关系的包通过软链的方式连接在一块,这一步类似于
npm link的作用; - 执行所有“被准备过”的 package 包的
npm run prepublish,以运行 prepublish 生命周期下的脚本 - 执行所有“被准备过”的 package 包的
npm run prepare,以运行 prepare 生命周期的脚本
-
--hoist当 packages/ 多个包有相同依赖时,可以通过加入参数
--hoist将公共依赖的部分 (Mostly-common dependencies) 提至项目顶层的 node_modules,以减少空间冗余。但是这种提升公共依赖的方法,可能会引入一些副作用。- Module resolution:当遇到没有遵循 查找 NPM 依赖关系 的项目或者第三方库时,可能会在使用过程中报错,提示找不到该模块。
- Forgetting dependencies: 如果开发人员出现疏忽,未在该 A 包中的声明该依赖,而在其他包中声明,由于第三方依赖被提升到项目 node_modules ,导致在本地环境中可用。而当 A 包单独发布时,由于未找到该依赖关系,导致实际使用过程中报错。
lerna version
keyword: update version from last release
这个命令主要会检查自上一次发布以来,仓库内发生了哪一些更新,并更新版本号。当执行这个命令时,主要会执行,详细的执行内容可以参阅 version life script:
- 检查自上一个版本依赖的更新内容
- 根据配置,更新版本号
- 执行声明周期脚本
- git commit 变更,以及对当前版本打上一个 tag
- git push 推送到远端仓库
通用配置
-
--allow-branch <branch-name>这个命令相当于是一个可执行
lerna version的分支白名单,如果未在这个白名单内,则无法执行该命令。lerna 会检查白名单分支,如果当前本地仓库分支未在该白名单列表内,则会被打断执行。这个配置通常在主干模型中十分有用,当限制只能由某些分支发布版本,避免任意分支都可以发布版本带来的混乱。<branch-name>支持 glob 匹配。这个命令通常可以在 lerna.json 中配置:
{ command: { version: { "allowBranch": ["master", "bugfix/*"] } } }需要注意的是,执行这个命令时,例如:
lerna version --allow-branch dev,lerna.json 的配置将会被覆盖,所以这个命令需要谨慎执行。 -
--conventional-commits在执行命令时,加上这个 flag,会让
lerna version遵循 Conventional Commits 规定,来生成对应的版本号以及 CHANGELOG.md 文件。注意:如果同时使用了
--no--changelog则会阻止该指令生成或者更新已有的 CHANGELOG.md 文件。 -
--ignore-changes <glob>在加入这个 flag 之后,lerna 在检查更新时,会默认忽视这些文件的更新。这个 flag 支持 glob 的匹配,在 lerna.json 中配置,则会默认忽视所有
_test_目录下的文件,详细的 glob 匹配可以自行查询相关写法。{ "ignoreChanges": ["**/_test_/**"] } -
--message <msg>这个 flag 实际上是
git commit -m一样的作用, 用来填写 commit message 的内容。lerna 提供了%s和%v两个占位符,使用%s则为带 'v' 的版本号,如v0.0.1; 如果使用%v则不带 'v', e.g0.0.1 -
--yes默认在交互式输入时,输入 yes,以跳过交互式输入的内容,在 CI 流水线中很有用。
-
--no-commit-hooks这个指令可以在配置了例如
husky之类的 git commit 钩子的仓库中使用,用来禁止lerna version在执行 git commit 的过程中触发相关的钩子,例如 commitmsg-lint 之类的钩子。
预发布
-
--preid <tag>这个 flag 实际上可以规定 pre-release 版本的前缀,如
lerna version --preid alpha,则默认预发布版本为alpha-0开始,如0.0.1->0.1.0-alpha.0。通常在使用过程中,可以和lerna publish --dist-tag <tag>搭配使用,这个参数和lerna publish中一致。 -
--conventional-prerelease将当前版本是作为一个 prerelease 的版本,而非直接升级大的稳定版本。在多分支开发中比较常用,例如有一个 dev、test、最终到 pro 正式发布,前置的测试流程可以使用这个 flag 来标记,这是一个预发布版本。也可以在后面带上参数,如
--conventional-prerelease=package1,package2,指定 package1,package2 为预发布版本。当搭配了
--conventional-commits,则版本号的升级规则会遵循语义化版本号 Conventional Commits 规定。
正式发布
-
--conventional-graduate如果曾经使用过 pre-release 则需要在正式发布的时候,加上这个 flag,让后续的 lerna publish 运作正确。
注意:如果使用过 pre-release, 而在正式版本发布前的
lerna version执行时,未加上--conventional-graduate。 则 lerna 默认会在之前的版本后面 +1, 即如果是0.0.1-alpha.0就会变成0.0.1-alpha.1。
lerna publish
keyword: publish in current repo
-
--from-packageor--from-git- 当没有加任何 flag 时,
lerna publish默认会发布自上次更新以来有更新的包; - 加上
--from-package,则会发布在 registry 没有的更新作为新的版本,当出现发布失败的情况,未能将包发布到 registry 时,这个指令将会非常有用; - 加上
--from-git, 则会发布当前 tagged 的 commit 作为新的版本。
所有版本发布过程中,仍会正常执行 npm 的 lifecyle script,除非在 lerna 中被
ignore-scripts手动禁止执行。 - 当没有加任何 flag 时,
-
--cananry加上这个标记之后, lerna 会以更加“精细”的版本命名来发布包,默认会在元后缀之后,附加当前的 git sha。例如
1.0.0变为1.1.0-alpha.0 + 77d227e3 -
--preid和
lerna version的同名参数不同,这个 flag 只在--cannry计算中生效,作为创建一个新的元后缀。但是,建议在实际过程中,如果均使用了 preid,则两个 preid 应保持一致。 -
--dist-tag <tag>使用此 flag 运行时,
lerna publish会使用给定的标记(默认为 lastest) 进行发布,这个选项在有多环境测试时,非常有用。可以避免用户升级到了 pre-release 的版本。如果用户是直接npm install pkg1则会下载到最新的稳定版本。如果用户需要特定的 feature 版本,或者是内部测试时,可以指定某个 tag,通过npm install pkg1@<tag-name>进行下载。🌰 在本人工作流的例子中,我们指定 dev 的 dist tag 为 alpha,则测试朋友可以通过下载
npm install pkg1@alpha来下载最新的 dev 环境版本。 -
--yes默认在交互式输入时,输入 yes,以跳过交互式输入的内容,在 CI 流水线中很有用。