monorepo
monolithic repository,单体仓库,把多个仓库放到了一个仓库来管理。
特别适合那些多个联系密切的包,React、Vue3,Jest,Next 等都采用这些方式
常规的 npm 包管理方式 multi repository
- 多个包独立存在,单独管理。比如当一个通用包变更后,依赖它的包需要修改,需要横跨多个项目,非常不利于维护,为什么不把他们放到一个仓库。
- 在多个包反复执行 npm publish 等操作
git submoudle
git submoudle 也可以实现多个仓库的管理,主项目通过 git submodule 方式引入
- 主项目保存了子项目的依赖链接,使用 git submodule update 要小心,不能搞乱了依赖关系。平常基本都是 git pull, 如果忘记 git submodule update 可能会把旧的submodule提交上去。
- git submodule 依然是多个仓库,仍会存在横跨多个仓库的来回修改的问题。
pnpm
快速的,节省磁盘空间的包管理工具。它具有 workspace 的能力。npm 从 7 开始也支持 workspace,当然 yarn 也支持。workspace 允许你从工作区链接这些 packages,多个 package 可以共享一套流程,比如eslint,git hook。
{
"dependencies": {
"svc": "workspace:^1.5.0"
}
}
在发布之后将会自动替换为正式的版本
{
"dependencies": {
"svc": "^1.0.0"
}
}
npm 、yarn 存在的问题
之前的 npm 结构是树形的,package.json 里的依赖包会被安装到 node_modules 一级目录,依赖包内部的子依赖会被安装到子包自己的 node_modules 中,这样一层一层,会占用大量的磁盘空间,其次就是这种层层的结构会造成引用路径过长。在 npm3 中 把依赖拍平了,依赖扁平化。
>
├── node_modules
├── lodash
| └── index.jss
| └── package.json
├── moment
├─ index.js
└─ package.json
- 幽灵问题
因为包被拍平了,会出现在 package.json 没有声明的情况下也可以使用其他包,你能访问到并不属于你自己的依赖。
- 分身问题
pac1 -> moment.js@1.0.0
pac2 -> moment.js@1.0.1
- 相同的包也会安装两次
- 依赖结构的不确定性,当项目中的依赖使用相同包时容易造成引用问题
├── node_modules
├── pac1
| └── index.js
| └── package.json
├── pac2
| └── node_module
| └── moment@1.1.0
└── index.js
└── package.json
├── moment@1.0.0
└── index.js
└── package.json
或者是这样呢
├── node_modules
├── pac1
| └── node_module
| └── moment@1.0.0
| └── index.js
| └── package.json
├── pac2
└── index.js
└── package.json
├── moment@1.1.0
└── index.js
└── package.json
取决于你package.json 中 pack1、pack2 的顺序,后来 npm 5 的时候增加了 lock 文件,来保证 node_module的确定性。npm,yarn 扁平化的安装机制造成包可以被访问问题,另外就是扁平化机制算法复杂,耗时长。
pnpm 登场
他不会重复对包进行安装,依赖被存储起来了,所有文件都被存储到硬盘的某个文职,下次你在安装的时候,会直接硬链接到这些文件。如果有一天你更新了某个依赖,新版本有文件改变了,pnpm会额外添加文件,只处理增量,不会再添加新版本的整个包。pnpm通过软硬链接的方式解决了幽灵依赖和npm包分身的问题。基于符号链接的 node_modules 结构
pnpm支持强大的过滤,允许将命令限制于包的特定子集。
pnpm run test --filter=@chehejia/idaas-sdk-app
changesets 版本发布管理
一切就绪,现在就差发布版本了。
常规情况下每个 package 是一个 repo,有自己的 commit 和 changelog,多包情况下每个 package 都需要有自己的版本号,有些工具可以通过 commit 自动生成 changelog,这种情况下不能用最外面的那个 commit 作为 changelog,需要针对每个 package 单独维护
workspace 中的包版本管理是一个复杂的任务,pnpm官方推荐 changesets 和 Rush,我们采用了 changesets。changesets 能灵活的控制每个包。
其他解决方案,比如 yarn workspace + lerna
利用 yarn workspace 能力,实现多个 packages 的共用,利用 lerna 进行版本管理。lerna 是一种针对多包管理工作流进行优化的工具,兼具版本管理的功能, lerna 曾宣布停止维护,后由 nrwl 公司接管继续维护。