一、项目中遇到的问题
最近在开发小程序的UI库,组件拆分力度比较细,都是一个个的单独的package包, 模块的复用性和灵活性达到最大化,实操的过程中,会遇到以下问题:
1、维护成本较高,任何的基层 repo 版本变更,将会引发一系列上层封装版本变动
2、版本发布npm包,代码不够规范,很多都不是发布master
3、一个包一个repo,每次需要找到对应的仓库
4、changelog 梳理异常折腾,有些基本上都没有changelog
基于上面的问题,有没有一种能解决我们问题的技术呢?
二、Monorepo 项目管理
Monorepo 的全称是 monolithic repository,即单体式仓库,与之对应的是 Multirepo(multiple repository),这里的“单”和“多”是指每个仓库中所管理的模块数量。
Multirepo 是比较传统的做法,即每一个 package 都单独用一个仓库来进行管理。例如:Rollup, ...,上面遇到问题的也是采用的这种方式。
Monorep 是把所有相关的 package 都放在一个仓库里进行管理,每个 package 独立发布。例如:React, Angular, Babel, Jest, Umijs, Vue ...
Multirepo和Monorep优劣势对比如下:
三、Monorepo 管理工具Lerna
Lerna 是一个管理多个 npm 模块的工具,是 Babel 自己用来维护自己的 Monorepo 并开源出的一个项目。优化维护多包的工作流,解决多个包互相依赖,且发布需要手动维护多个包的问题。
Lerna 现在已经被很多著名的项目组织使用,如:Babel, React, Vue, Angular, Ember, Meteor, Jest 。
1、lerna模式
在初始化一个项目之前我们必须要清楚,lerna 对管理 monoRepo 有两种模式
- Fixed/Locked mode (default)
- Independent mode
Fixed/Locked 模式
: 官方默认推荐模式,当前 babel 的项目管理模式,在该模式下所有的 packages 都会遵循一个版本号,该版本号维护在 lerna.json
的 version 字段中,当需要版本发布时 lerna publish
时,如果一个模块和上一次 release 相比有过变更的话,会自动发布一个新版本。
这种模式的问题在于:当有一个 major 变更的时候,所有 packages 都会都会有一个新的 major 版本。
维护团队认为:版本是一种非常 cheap 的东西,所以不必纠结。
Independent 模式
: 在该模式下所有 packages 新版本的生成将会由开发者决定,lerna.json
的 version 字段也会随之失效。这种模式的弊端非常明显,开发者必须要非常清晰该发什么版本,事实上在多人协作项目上很难做到这一点。
2、如何使用lerna
a、全局安装lerna
npm i -g lerna
b、初始化项目
mkdir lerna-repo && cd $_
npx lerna init
初始目录如下,接着进行开发
c、建立 packages 的依赖关系
lerna bootstrap
这个命令会安装好所有 packages 的依赖,以及建立好 packages 相互依赖的软连接
正式流程为:
- 安装所有 package 的外部依赖.
- 对存在相互依赖的 package 创建软连接.
- 在所有已经 bootstrapped 的 package 中执行 npm run prepublish.
- 在所有已经 bootstrapped 的 package 中执行 npm run prepare.
当然我们使用 --hoist 来把每个 package 下的依赖包都提升到工程根目录,来降低安装以及管理的成本。
lerna bootstrap --hoist
如果以前安装了依赖,发生改动,可以先清理一下安装的依赖即可:
lerna clean
d、发布版本
lerna publish
正式流程为:
- 执行 lerna updated 来确定哪些包需要被发布.
- 如有必要会升级 lerna.json 的 version 字段。
- 对所有需要 update 的 package 进行版本的更新,并写入他们的 package.json.
- 对所有需要 update 的 package 进行依赖申明 specified with a
caret (^)
. - 创建一个 git commit 和 tag
- 把包发布至 npm
四、生成changelog
由于本项目后期需要对外,使用基于PR来生成changelog的lerna-changelog,项目建议使用cz-lerna-changelog 。
1、安装lerna-changelog
npm install lerna-changelog --save-dev
2、修改 lerna.josn
需要新增相关 lerna-changelog 所需要的配置,此处参考babel配置
"changelog": { "repo": "binglingwy/lerna-test-new", "cacheDir": ".changelog", "labels": { "PR: Breaking Change :boom:": ":boom: Breaking Change", "PR: New Feature :rocket:": ":rocket: New Feature", "PR: Bug Fix :bug:": ":bug: Bug Fix", "PR: Docs :memo:": ":memo: Documentation", "PR: Internal :house:": ":house: Internal", "PR: Performance :running_woman:": ":running_woman: Performance" } },
注意:labels 的 key 必须在 github 的仓库内定义好
3、设置令牌
export GITHUB_AUTH="..."
GITHUB_AUTH 的 token 字段可以在github 申请 token 获得。
4、创建个PR
a、拉一个新的分支
b、修改代码并提交,提交记录记得关联issues,例如:
git commit -a -m "module-base: bug fixed, Close #1"
c、推送代码,并在github上创建PR
注意:在创建 pr 时一定要选择对应的 label ,label需提前在github建好,跟lerna.josn一致
d、合并pr到主干,切换到本地master,生成changelog
node_modules/.bin/lerna-changelog
e、一旦 publish 后我们便可以创建 release note,效果如下
当然也可以在生成文件CHANGELOG.md,在lerna.json中添加conventionalCommits配置:
"command": { "publish": { "allowBranch": "master", "conventionalCommits": true } }
配置后,当我们执行lerna publish
后会在项目根目录以及每个packages
包下,生成CHANGELOG.md
。
注意: 只有符合约定的commit
提交才能正确生成CHANGELOG.md
文件。
参考文章
Lerna 官网:https://github.com/lerna/lerna/blob/master/README.md
lerna-changelog:https://github.com/lerna/lerna-changelog
手摸手教你玩转 Lerna: http://www.uedlinker.com/2018/08/17/lerna-trainning/