Sparkee是一个类似lerna的monorepo管理工具,但又有很多不同,本文将详细介绍本人开发sparkee的初衷以及该工具的具体使用场景。
为什么要造轮子
造轮子的初衷无非无非就是现有的工具不好用或不能满足自己的项目场景。在我自己的monorepo项目中有以下几点是lerna等monorepo工具无法解决的:
pnpm局限性
项目使用pnpm自带的monorepo
功能进行依赖管理和同仓多项目
管理,但pnpm的版本管理和发布功能却十分鸡肋,无法查看当前monorepo
下package
的版本和相互依赖关系,且发布只有pnpm publish
发布全部package或使用--filter
指定package发布,至于版本自增
、changelog
等发布工作流自己配合changesets
和Rush
使用。
lerna局限性
lerna
在发布工作流就做的很好,上述pnpm的局限性貌似可以解决,但在项目具体使用中发现以下问题:
-
lerna
的monorepo
管理方式是统一开发、统一发布,比较典型的是babel这个大型monorepo
,每个package
的依赖关系极强,因此一个release发布需要涉及全部package
的发布。但在我的实际项目中,每个package
确实存在依赖关系,但一旦只有一个package
发生变动,这个package
发布时我是不希望其余package
只是修改版本然后发布一次,相比我更希望支持pnpm --filter <package> publish
的方式,很遗憾lerna不支持这个特性。 -
lerna
不支持workspace
协议。pnpm
的monorepo
管理支持使用workspace
协议,在package.json
中使用"foo": "workspace:*"
的方式调用package
,因此在执行pnpm publish
时pnpm会自动修改package
的当前版本号,无需担心workspace
关键字会发布到release版本的package.json
中。遗憾的是lerna已经停止新功能迭代,无法对workspace
协议进行支持,在lerna-lite 号称可以支持workspace
协议协议,兼容lerna命令,但在具体使用时发现lerna-lite
依然会在发布时强制把package
的本地package.json
文件里的workspace
关键字去掉再进行发布,因此lerna-lite
也不能很好的兼容workspace
协议发布。
此时sparkee
就是基于pnpm publish
保留workspace
协议但又能很好的支持lerna发布工作流而开发的monorepo
版本管理工具
sparkee特性
-
相比
lerna
复杂而且冗长的命令,sparkee
命令很简单,目前只有三个命令:sparkee init
,sparkee info
和sparkee publish
-
支持
workspace
协议,执行sparkee publish
其实内部调用的是pnpm publish
,因此无需担心项目内workspace
被影响 -
发布支持
版本自增
、自动提交tag
、changelog自动生成
,符合lerna标准发布工作流,弥补pnpm
发布管理短板 -
支持单个
package
发布 -
支持
package
版本查看以及树状依赖关系图
sparkee支持的项目结构
sparkee
需要在标准monorepo
项目结构下工作,即package
需要统一放在packages
下,每个package
维护自己的package.json
:
your-repo/
package.json
packages/
package-1/
package.json
package-2/
package.json
这里需要注意的是
sparkee
将package.json
内的name
作为package
的名称,而不是目录名,这一点和pnpm
规则是一样的
这里我展示具体demo的项目结构:
pnpm-monorepo
├── package.json
├── packages
├── pkg1
| └── package.json // name: @geocld/pkg1
└── pkg2
└── package.json // name: @geocld/pkg2
安装
sparkee
支持全局安装或在项目内安装使用:
$ npm i sparkee -g
$ npm i sparkee --save-dev
或者通过pnpm add
将sparkee
安装在最外层:
$ pnpm add sparkee -w
安装完成后可以通过sparkee
或spk
执行sparkee
安装在项目内使用
npx sparkee
或npx spk
sparkee init
sparkee init
会初始化当前monorepo
,init过程用户指定选择管理当前packages
下的package
,或者管理全部:
$ npx sparkee init
初始化完成后项目根目录会生成一个spark.json
,内容即刚才选择需要管理的模块:
// spark.json
{
"packages": [
"@geocld/pkg1",
"@geocld/pkg2"
]
}
sparkee info
sparkee info
可以查看当前packages
的版本信息,可选项--tree
展示packages
的依赖树关系。
$ sparkee info <--tree>
info
info -- tree
sparkee publish
sparkee publish
是sparkee
的核心,其遵循了模块发布的标准工作流。
执行sparkee publish
时,其内部主要做了以下工作:
- 通过比较最近一次的
tag
检测到最近一次提交变动的项目(src
文件夹和package.json
),如果没有发布过tag则以第一次commit
做比较 - 选择需要发布的模块,可以发布单个或多个模块
- 自动更新
package
下package.json
的版本号 - 通过
conventional-changelog
在选定发布的package
中生成changelog,注意changelog
需要git commit
符合Angular提交规范,否则得到的changelog可能是空的 - 自动依次执行
git Commit
、git tag
、git push
- 通过
pnpm
进行发布
完整的sparkee
工作流如下:
demo:
总结
可以说Sparkee是为了完善pnpm
发布而开发的版本发布工具,如果你的项目使用了pnpm
,同时希望得到有别于lerna的版本发布方式,那么可以试一下sparkee
。如果你对这个项目感兴趣,可以随时对本项目发起pr以完善sparkee
的功能和使用体验。
(完)