什么是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/**'
我们就可以在packages目录下创建多个模块,这里我创建了charts、components、utils3个包
安装全局依赖
安装packages目录下模块共用的依赖包
示例:安装lodash
安装全局pnpm
npm i pnpm -g
安装lodash
pnpm install lodash
执行上面安装命令,会报错如下:
如果想把它安装到根目录下,执行命令时需要增加
-w标识(或者 --workspace-root)
pnpm install lodash -w
可以看出,得益于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的地方就会实时更新。
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 目录,里面会生成一个 changeset 的 config.json 文件。
pnpm changeset init
根据自己配置,修改config.json文件中的配置:
- changelog: changelog 生成方式
- commit: 不要让 changeset 在 publish 的时候帮我们做 git add
- linked: 配置哪些包要共享版本
- access: 公私有安全设定,内网建议 restricted ,开源使用 public
- baseBranch: 项目主分支
- updateInternalDependencies: 确保某包依赖的包发生 upgrade,该包也要发生 version upgrade 的衡量单位(量级)
- ignore: 不需要变动 version 的包
生成变更集
执行命令pnpm changeset 或 pnpm changeset add,该命令将询问一系列问题,首先是您要发布的包,然后是每个包的semver bump类型,然后是整个变更集的摘要。在最后一步,它将显示它将生成的变更集,并确认您要添加它。
pnpm changeset
# 或者
pnpm changeset add
最后生成的文件:
发布
执行命令pnpm changeset publish进行包的发布
pnpm changeset publish
总结
组件库开发涉及到多包时,还是建议使用monorepo的方式,更方便依赖的管理。