pnpm + monorepo + changeset实现多包管理和发布

8,112 阅读4分钟

什么是monorepo

monorepo意为『单一代码库』,对应的则为『多代码库』(multirepos)。

monorepo单一代码库是在一个代码库(repo)里包含了多个模块/包(package)。这些模块/包虽然有可能是相关的,但通常在逻辑上是相互独立的。比如vue代码库packages目录下包含了很多核心模块,彼此相关,又彼此独立。

├── packages
|   ├── pkg1
|   |   ├── package.json
|   ├── pkg2
|   |   ├── package.json
├── package.json

vs 多代码库

多代码库(`multirepos)指的是每个项目都单独存在一个完全独立的代码库中。

大多数的项目都是多代码库的,相对独立,每个项目可以自由选择使用的技术栈,项目体积也相对较小。

优点

  • 一个代码库内维护多个模块/包,便于查找
  • 方便版本管理和依赖管理,模块之间的引用和调试也更加方便
  • 统一代码库中的编码风格
  • 统一的代码构建流程
  • 统一生成 changeLog

缺点

  • 代码库体积变大,导致一些操作、启动项目等变慢
  • 主线破坏会影响到每一个单独模块开发的人
  • 代码提交影响人员范围更大

结论

组件库开发更适合monorepo单一代码库的方式,项目开发更适合multirepos多代码库的方式。

pnpm实现monorepo

关于pnpm的介绍和用法,这里不赘述了,可以看之前的文章:2022年了,你还没用pnpm吗?

初始化

初始化生成package.json文件

pnpm init

pnpm-workspace.yaml

新建pnpm-workspace.yaml文件,定义工作空间的根目录,并能够使您从工作空间中包含 / 排除目录 。 默认情况下,包含所有子目录。

packages: # 所有在 packages/ 子目录下的 package
- 'packages/**'
# 不包括在 test 文件夹下的 package
- '!**/test/**'

image.png

我们就可以在packages目录下创建多个模块,这里我创建了chartscomponentsutils3个包

image.png

安装全局依赖

安装packages目录下模块共用的依赖包

示例:安装lodash

安装全局pnpm

npm i pnpm -g

安装lodash

pnpm install lodash

执行上面安装命令,会报错如下:

image.png 如果想把它安装到根目录下,执行命令时需要增加-w标识(或者 --workspace-root

pnpm install lodash -w

image.png

image.png

可以看出,得益于pnpm的包管理机制,node_modules目录下只展示了lodash一个依赖包,lodash的相关依赖包完全没展示在其中,全都展示在了.pnpm里面,再通过软链接的形式指向真实的地址,简洁分明,避免了互相依赖的情况。

安装局部依赖

安装packages目录下每个包的依赖

示例:packages/charts目录安装echarts

# 进入目录
cd packages/charts
# 安装依赖
pnpm install echarts

安装项目间依赖

packages目录下的模块之间相互引用,怎么安装呢?

比如charts模块依赖utils模块,为了让依赖实时更新最新版本,使用用通配符更新版本。

pnpm add utils@* --filter charts

执行完上述命令,就会在charts模块安装utils的依赖,如下图,我们可以在package.json中的dependencies看到"utils": "workspace:*",这里的workspace:*匹配的就是本地包,node_modules目录下也生成了utils的软连接,utils包一更新,charts里引用utils的地方就会实时更新。 image.png

workspace是局部依赖,pnpm publish会转成真实路径依赖。

monorepo发包changeset

经过上面的步骤,我们已经完成了monorepo搭建,接下来我们看一下怎么去发布packages目录下的包。

Changesets 是一个用于 monorepo 项目下版本以及 changelog 文件管理的工具。管理monorepo 项目下子项目版本的更新、changelog 文件生成、包的发布。

github地址 changesets,在 github 上有大约 快 5k 的 star。

安装

根目录下执行下述命令安装@changesets/cli

pnpm install @changesets/cli -w  --save-dev

初始化

执行命令 pnpm changeset init进行初始化,在项目根目录下生成一个 .changeset 目录,里面会生成一个 changesetconfig.json 文件。

pnpm changeset init

image.png

image.png

根据自己配置,修改config.json文件中的配置:

  • changelog: changelog 生成方式
  • commit: 不要让 changeset 在 publish 的时候帮我们做 git add
  • linked: 配置哪些包要共享版本
  • access: 公私有安全设定,内网建议 restricted ,开源使用 public
  • baseBranch: 项目主分支
  • updateInternalDependencies: 确保某包依赖的包发生 upgrade,该包也要发生 version upgrade 的衡量单位(量级)
  • ignore: 不需要变动 version 的包

生成变更集

执行命令pnpm changesetpnpm changeset add,该命令将询问一系列问题,首先是您要发布的包,然后是每个包的semver bump类型,然后是整个变更集的摘要。在最后一步,它将显示它将生成的变更集,并确认您要添加它。

pnpm changeset

# 或者

pnpm changeset add

image.png

最后生成的文件:

image.png

发布

执行命令pnpm changeset publish进行包的发布

pnpm changeset publish

总结

组件库开发涉及到多包时,还是建议使用monorepo的方式,更方便依赖的管理。

参考文档