本文最后更新于 <span id="expire-date"></span> 天前,文中部分描述可能已经过时。

引言

闲话休提。想来看这篇文章的人已经对 Monorepo 有所耳闻,想必也不需要大量话语来论述其利弊,所以我们直接开始吧。

创建 workspace

首先我们需要初始化项目,pnpm init,如果做过这一步就直接往下。
然后在项目根目录添加 pnpm-workspace.yaml,填入如下内容:

packages:
- 'packages/*'

然后在项目根目录创建 packages 文件夹。

创建 package

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。

安装 workspace 内的其他模块

当执行安装命令的时候,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 等等。

结语

重点就是这些,讲完了。

本文作者:AkaraChen

本文链接: https://blog.akr.moe/pnpm-monorepo.html