Monorepo
Monorepo 是管理项目代码的一个方式,指在一个项目仓库 (repo) 中管理多个模块/包 (package),不同于常见的每个模块建一个 repo
├── packages
| ├── pkg1
| | ├── package.json
| ├── pkg2
| | ├── package.json
├── package.json
monorepo 最主要的好处是统一的工作流和Code Sharing。比如我想看一个 pacakge 的代码、了解某段逻辑,不需要找它的 repo,直接就在当前 repo;当某个需求要修改多个 pacakge 时,不需要分别到各自的 repo 进行修改、测试、发版或者 npm link,直接在当前 repo 修改,统一测试、统一发版。只要搭建一套脚手架,就能管理(构建、测试、发布)多个 package。
但是 repo 的体积较大。因为各个 package 理论上都是独立的,所以每个 package 都维护着自己的 dependencies,而很大的可能性,package 之间有不少相同的依赖,而这就可能使install
时出现重复安装。目前最常见的 monorepo 解决方案是 Lerna 和 yarn
的 workspaces
特性。
lerna
lerna是一款js代码库管理软件, 用来对一系列相互耦合比较大、又相互独立的js git库进行管理。解决各个库之间修改混乱、难以跟踪的问题。
lerna管理的项目结构
- packages
- project1
- src
- index.ts
- package.json
- project2
- src
- index.ts
- package.json
- project3
- src
- index.ts
- package.json
- lerna.json
- package.json
不会变化了, 默认为independent。
lerna.json解析
{
"version": "1.1.3",
"npmClient": "npm",
"command": {
"publish": {
"ignoreChanges": [
"ignored-file",
"*.md"
]
},
"bootstrap": {
"ignore": "component-*",
"npmClientArgs": ["--no-package-lock"]
}
},
"packages": ["packages/*"]
}
- version , 当前库的版本
- npmClient , 允许指定命令使用的client, 默认是 npm, 可以设置成 yarn
- command.publish.ignoreChanges , 可以指定那些目录或者文件的变更不会被publish
- command.bootstrap.ignore , 指定不受 bootstrap 命令影响的包
- command.bootstrap.npmClientArgs , 指定默认传给 lerna bootstrap 命令的参数
- command.bootstrap.scope , 指定那些包会受 lerna bootstrap 命令影响
- packages , 指定包所在的目录
yarn workspace
yarn 作为包管理器的同学,可以在 package.json 中以 workspaces 字段声明 packages,yarn 就会以 monorepo 的方式管理 packages。相比 lerna,yarn 突出的是对依赖的管理,包括 packages 的相互依赖、packages 对第三方的依赖,yarn 会以 semver 约定来分析 dependencies 的版本,安装依赖时更快、占用体积更小;但欠缺了「统一工作流」方面的实现。
workspace的作用:
(1)能帮助你更好地管理多个子project的repo,这样你可以在每个子project里使用独立的package.json管理你的依赖,又不用分别进到每一个子project里去yarn install/upfrade安装/升级依赖,而是使用一条yarn命令去处理所有依赖就像只有一个package.json一样
(2)yarn会根据就依赖关系帮助你分析所有子project的共用依赖,保证所有的project公用的依赖只会被下载和安装一次。
开启 workspace 的功能也比较简单,只需要在 package.json 里面将 private 设置为 true,并且规定好 workspaces 字段里面的子项目就好了。
{
...
private: true,
workspaces: [
"packages/*"
]
}
yarn workspace 命令
yarn workspace 提供了一些常用的命令。
一般来说,执行某个项目下面的某个命令都用 yarn workspace project run xxx。
执行所有项目下面的某个命令要用 yarn workspaces run xxx。
举例
用 monorepo 的形式来管理这个仓库。
由于他们使用了相同的技术栈,那么 eslint、prettier,甚至 webpack 配置都可以提取到最外面,不用维护在每个项目里面。
以 create-react-app eject 之后的配置为例:
- node_modules
- react
- react dom
- redux
- lodash
- packages
- project1
- package.json
- project2
- package.json
- config
- webpack.config.js
- webpack.dev.config.js
- scripts
- create.js
- bin.js
- build.js
- start.js
- .eslintrc.js
- .prettierrc
- commitlint.config.js
- jest.config.js
- tsconfig.js
- package.json
- yarn.lock
我们可以看到,通用配置都被提取到了最外层。
如果运行或者构建子项目,只需要在子项目的 package.json 里面这么配置。在外面执行 yarn workspace project run build
就行了。
"start": "node ../../scripts/start.js",
"build": "node ../../scripts/build.js",
"test": "node ../../scripts/test.js
由于 yarn workspace 和 lerna 有较多的功能重叠,这里重叠的部分优先使用 workspace 。最后就是只有发布管理使用了 learn 其它使用 workspace