在讲 monorepo 之前,我们先思考个问题,多个项目之间如何复用代码?
代码复用
当公司的项目越来越多,项目中的配置文件、业务组件、Hooks、Utils 如何在多个项目中复用?
npm
复用文件抽离成 npm 包的方式在不同项目中引用
缺点:
1、npm 包中一般不写业务逻辑,而我们大部分业务逻辑是需要共用的
2、一旦 npm 包发布新版本,所有项目都要重新下载最新版本
git submodule
复用文件单独放在一个git,其他项目使用 git submodule 复用代码
缺点:
如果公共 git 中有文件更新,其他所有仓库也需要手更新最新的 commitId
以上两种都可以解决代码复用,但如果有几十个、上百个项目,则需要去每个项目中去更新 npm 版本、以及 git commitId,过程漫长且繁,很容易出现问题
有没有更好的复用方式? 答案就是我们今天的主题 monorepo
mono-repo
monorepo 可以使用 turborepo、lerna、yarn、pnpm 来管理,我们今天讲 pnpm 如何管理 monorepo 项目,为什么选择 pnpm,大家可以看下我的往期文章,有详细的 pnpm 介绍,链接地址: pnpm
创建项目
1、这里默认都有 pnpm 环境,首先初始化项目
pnpm init
生成 package.json 文件
{
"name": "monorepo-pnpm",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
2、创建pnpm-workspace.yaml文件,定义工作空间的根目录为 packages
packages:
- 'packages/**'
3、在工作空间 packages 下创建多个子项目
├── package.json
├── packages
│ ├── components
│ │ ├── index.js
│ ├── hooks
│ │ ├── index.js
│ └── project
│ ├── index.js
└── pnpm-workspace.yaml
4、初始化子项目,这里以 project 为例,执行pnpm init生成package.json文件
{
"name": "@packages/project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
项目之间复用
在 project 项目中复用 components,在根目录下执行
pnpm add @packages/components@* --filter @packages/project
执行完后的package.json
{
"name": "@packages/project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@packages/components": "workspace:*"
}
}
可以看到已经将 components 作为依赖项,其中workspace:*将在发布中转换成最新版本
"dependencies": {
"@packages/components": "workspace:*"
}
// pnpm publish 后会被转换成
"dependencies": {
"@packages/components": "1.0.0"
}
这样我们修改了 @packages/components,所有子项目都会自动同步最新版本代码
当然monorepo的好处不仅仅是方便的做代码复用,它还可以更好的统一编码规范,以及减少开发一个需求在多个 git 仓库之间的频繁切换,减少心智负担