闲话休提。想来看这篇文章的人已经对 Monorepo 有所耳闻,想必也不需要大量话语来论述其利弊,所以我们直接开始吧。
首先我们需要初始化项目,pnpm init
,如果做过这一步就直接往下。
然后在项目根目录添加 pnpm-workspace.yaml
,填入如下内容:
packages:
- 'packages/*'
然后在项目根目录创建 packages
文件夹。
在 packages
文件夹下创建子目录,比如 web
或者 core
:
cd packages
mkdir web
cd web
在此目录再次执行 pnpm init
,这就是你的第一个 package。
此时查看 <root>/packages/web/package.json
,其 name 字段就是这个 package 的名称。
同样的操作,换成不同的目录,就可以创建其他 package。
有些包在整个项目都要用,比如 eslint,我们可以把它安装在 workspace 中:
pnpm add -w eslint
给原有的安装命令加上 -w
标记即可将依赖安装在工作区。
有些依赖在前端会用到,但是后端用不到,我们就可以仅在前端安装:
pnpm add react -r --filter web
同样的,给命令加上 -r
即可指定将包安装在子模块中,然而这样是给所有子模块安装,不符合意图,所以需要使用另一个参数 --filter
来指定某个 package。
类似的,不仅仅是安装依赖,其他命令比如 pnpm run
也是同理,pnpm run -w lint
仅执行 workspace 的 lint
script,pnpm run -r dev
是启动所有模块的 dev script。
当执行安装命令的时候,pnpm 会优先查找当前 workspace 是否有名称一样的依赖,然后才会去 npm 仓库,所以我们执行如下命令:
pnpm add core -r --filter web
这会将 core 安装为 web 的依赖,打开 web 的 package.json,我们发现依赖中多了这个:
"core": "workspace:^1.0.0"
注意这里的 workspace,这表明这个包是从工作区中安装的。
然后我们可以直接在 web 子模块下导入 core 的文件:
/* <root>/packages/web/index.js */
import core from 'core'
然而这种情况下,子模块的名称跟 npm 上的包重名可能会很麻烦,所以很多项目的子模块的 package name 都会加上 team 名,比如 @devteam/core
等等。
重点就是这些,讲完了。