主流的 monorepo 做法是只有一个 git 仓库,然后建立一个 packages 目录,每个子目录都是一个 npm package,有自己的 package.json。
如果我们不用这个主流做法,而是每个 npm package 都有一个自己的 git 仓库,该如何维护 package.json 文件?
假设我们有 pkg-a,pkg-b,pkg-c 三个包,彼此有依赖关系。
列举可能遇到的问题:
拆分成多个 git 仓库之后,所有问题的实质都是单个 git 仓库的代码都是不完整的,必须组合了其依赖之后,才能跑单元测试
每个包,都有两个形态
yarn 具有 workspaces 的功能。可以写一个 project 级别的大 package.json,把一堆小的 workspaces 给整合起来,选择每个包是从 git 拉,还是从 npm registry 来拉。
下面我们来看具体的解法。
pkg-a 的 package.json 这么写
"name": "pkg-a" , "version" : "0.1.0" , "peerDependencies" : { "pkg- b ": "*" , "pkg-c" : "*"这么写的道理是:
然后建立这样的本地开发目录结构
project ->
package.json
packages ->
pkg-a (git submodule)
pkg-b (git submodule)
pkg-c (git submodule)
在 project/package.json 这么写
"private": true,
"name": "project",
"workspaces": ["packages/*"]
workspaces 是 yarn 的功能。当在 project 目录下执行 yarn install 的时候。会让 pkg-a,pkg-b,pkg-c 互相都依赖本地 workspaces 里指定的文件夹。
packages 目录下的 pkg-a 和 pkg-b 这些都是 git submodule,需要独立 git commit 和 git push。
如果不希望使用本地的 pkg-c,而是指定一个 npm registry 上的版本,可以不建立 packages/pkg-c 这个 submodule,然后修改一下 package.json
"private": true,
"name": "project",
"workspaces": ["packages/*"],
"dependencies": {
"pkg-c": "0.1.0"
这样我们就可以避免 submodule 越来越多的问题。同时也避免了单 git 仓库的 monorepo 越来越大的问题。可以自由选择把多少 pkg 用 git submodule 拉到本地来协同修改。
那么在 CI 服务器上,pkg-a 如何跑自己的单元测试呢?只有 peerDependencies 无法 yarn install 自己的依赖啊。
可以在 pkg-a 的目录下,新建一个 pkg-a/ci/package.json 文件
"private": true,
"workspaces": [".."],
"scripts": {
"postinstall": "cd .. && rm -rf node_modules && ln -s ci/node_modules"
"dependencies": {
"pkg-b": "git://github.com/xxx/pkg-b.git",
"pkg-c": "git://github.com/xxx/pkg-c.git"
"resolutions": {
"pkg-b": "git://github.com/xxx/pkg-b.git",
"pkg-c": "git://github.com/xxx/pkg-c.git"
在 ci 脚本中,切换到 pkg-a/ci 子目录去做 yarn install,而不是在 pkg-a 自己这层目录做 yarn install
name: Continuous Integration
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 15.5.0
- run: cd ci && yarn
- run: yarn ci
如果不加 resolutions 也可以,就是会报 warning。
其中 postinstall 这个 script 是为了修复 pkg-a/node_modules 里的内容不正确的问题。一般 workspaces 是不会写 ".." 这样的路径的。属于 yarn 没有考虑过的使用方式。
使用 peerDependencies 和 * 放宽对依赖的版本约束,免得天天改 package.json
使用 yarn workspaces 链接本地的多个开发中的 package 目录
给 CI 跑测试单独建一个 ci/package.json 指定 CI 时的依赖版本
抄作业:github.com/rotcare/rx-…