介绍
pnpm 内置了对 monorepo1 的支持,通过该支持,可以实现一个存储库(workspace)存放多个项目。
workspace 协议
优先装本地的 package
在
.npmrc里指定link-workspace-packages为true,可以使 workspace 内的 package 安装依赖时优先查找当前 workspace 里的 package。假如 workspace 里有个
barpackage 依赖foopackage,并且 workspace 里存在一个foopackage,然后这个foo版本为1.0.0,那么当barpackage 安装foo@1.0.0依赖项时,会优先安装这个 workspace 里的foopackage。但是如果barpackage 安装foo@2.0.0,那么由于 workspace 里的foopackage 版本对不上,就会去找 npm 上的foo@2.0.0package 进行安装。所以这个配置有可能带来未知的结果。
关于 workspace 的设置可以参考:.npmrc | pnpm
要依赖 workspace 内其他 package,可以像这样添加依赖项: "foo": "workspace:*"。这表示依赖 workspace 内的 foo package,并且不限定版本。
如果想以别名的方式使用依赖,可以像这样添加依赖项:"@repo/foo": "workspace:foo@*"。
在发布的时候,别名会被转成常规的别名依赖项,像上面的会转成:"@repo/foo": "npm:foo@1.0.0"。
命令行里的安装方式
需要注意的是在命令行里安装好像指定不了具体版本,不管指定
*还是具体版本名,添加到package.json里都是^版本。# 以依赖名的方式安装 # 相当于 "foo": "workspace:^" pnpm i foo@workspace:^ # 以别名的方式安装 # 相当于 "@repo/foo": "workspace:foo@^" pnpm i @repo/foo@workspace:foo@
以相对路径的方式依赖 workspace package
假设当前 workspace 有两个 package:
+ packages
+ foo
+ bar
bar 的依赖项中可能有 foo 声明为 "foo": "workspace:../foo"。在发布之前,这些依赖声明会转成为所有包管理器支持的常规版本规范。
发布 workspace packages
当 workspace package 打包到存档中时(无论是通过 pnpm pack 还是诸如 pnpm publish 之类的发布命令之一),会通过以下方式动态替换任何工作区:依赖项:
- 目标工作区中对应的版本(如果使用
workspace:*、workspace:~或workspace:^) - 关联的 semver 范围(对于任何其他范围类型)
例如,如果工作区中有 foo、bar、qar、zoo,它们的版本均为 1.5.0,像下面这样:
{
"dependencies": {
"foo": "workspace:*",
"bar": "workspace:~",
"qar": "workspace:^",
"zoo": "workspace:^1.5.0"
}
}
那么打包时会自动转换成像下面这样:
{
"dependencies": {
"foo": "1.5.0",
"bar": "~1.5.0",
"qar": "^1.5.0",
"zoo": "^1.5.0"
}
}
这个功能允许你依赖本地 workspace package,同时仍然能够将生成的 package 发布到远程注册表,而无需中间发布步骤,package 的用户将能够像任何其他 package 一样使用你发布的 workspace,仍然受益于 semver 提供的保证。
Release workspace
对 workspace 内的 package 进行版本控制是一项复杂的任务,pnpm 目前没有为此提供内置解决方案。然而,有两个经过充分测试的工具可以处理版本控制并支持 pnpm:
- changesets:用法可以参考 pnpm
- Rush:用法可以参考 Setting up a new repo | Rush
故障排除
如果 workspace 依赖项之间存在循环,pnpm 无法保证脚本将按正常顺序运行。如果 pnpm 在安装过程中检测到循环依赖关系,它将产生警告。如果 pnpm 能够找出哪些依赖项导致了循环,它也会显示它们。
Footnotes
-
又称多包存储库、多项目存储库或整体存储库 ↩