问题的诞生
日常中会写封装很多工具库,用于避免日后出现同样的功能,当这些工具库需要版本管理的时候,一种做法是把它们放在 SVN 上,但是更多的企业会选择 git 作为版本管理工具,这时候就需要考虑一些问题了,是把每一个工具库放在单独的仓库种还是把多个模块放在同一个仓库中呢,两种方案都有各自的优缺点:
Multirepo 模式
每个模块都独立一个仓库,只需要关注这个模块的功能,当出现依赖其他模块的时候,上线前其它依赖也要保证在线上,当基础库多了的时候 git 仓库也会增多,增加了维护的难度。
Monorepo 模式
多个模块公用一个仓库,减少了 git 仓库。
两则之间大部分其它的优势对方基本都能实现,所以我认为最大的好处就是减少了 git 仓库数量,但是当出现了 yarn 的 workspace 之后,monorepo 方式变得更受欢迎了。
Yarn workspaces
yarn workspaces 是一种管理软件包的方式,它通过 package.json 来管理所有的模块,并且通过 yarn install 就能安装所有的依赖,当出现某一个模块依赖另一个的时候, 会自动匹配当前 workspace 下的这个模块,而不会到 npm 仓库中去下载,极大的提升了调试效率,看看官网的解释:
- 当多个依赖包相互依赖的时候,这种方式比直接 link 更好,它只会影响当前依赖树,而不会影响到系统的依赖。
- 所有的依赖被安装在一个 node_modules 下,通过 yarn 直接管理。
- Yarn 将使用一个单一的 lock 文件,而不是每个项目多有一个,这意味着更少的冲突和更容易进行代码检查。
Lerna
还可以更激进一点,在 yarn workspaces 之上, lerna 提供了一些更加高级的功能,比如直接提交到 git 和 npm 仓库,创建软件包等等,已经有很多大型的开源项目使用它来维护各个依赖库:babel、taro、umi 等等
Vrdaccio
Vrdaccio 是一个用于搭建私有 npm 仓库的工具,它支持 Docker 和 K8s 等部署方式,官方有非常详细的步骤,当一些依赖库与业务关联较大,所以放到公有的 npm 仓库并不合适。当公有仓库中的软件包和私有的起冲突了怎么办?比如:当出现私有依赖包和公有的同名了,毕竟前端的包可没有什么 "com.locals.xxx" 的命名方式啊,出现同名的几率还是蛮高的。
npm-scope
刚开始搭建私有仓库的时候我们出现了问题,我们得把全局的 registry 设置成我们私有的地址,或者每次 install 的时候都带上私有地址,避免在淘宝或 npm 源上找不到,但是这种方案有一些问题:
- 下载公有依赖的时候要先经过私有仓库,多了一道工序
- 会把所有的依赖都缓存到服务器,导致占用空间比较大。
- 设置全局的会影响其他项目,因为并不是所有项目都用到私有库中的包。
- 私有库在内网,外网访问较慢
npm 提供了 scope 功能,必须 @babel/babel-core, @babel 就是它的 scope,并且允许对特定 scope 使用指定的源地址:
npm config set @myco:registry http://reg.example.com
所以对于私有包,应该设置统一的 scope,以方便它人使用。
总结
以上几种方式基本能解决代码管理、仓库管理的问题。