pnpm workspace 的工作原理
1. 基本概念
pnpm workspace 是一种用于管理多个包(packages)的特性,特别适合单体仓库(monorepo)的场景。它允许在一个仓库中管理多个项目,共享依赖关系,并简化开发流程。
pnpm 通过 硬链接(hard links)
和 符号链接(symlinks)
实现依赖的高效管理:
-
硬链接:所有子包共享同一份依赖文件,通过硬链接指向全局存储(.pnpm-store),极大节省磁盘空间。
-
符号链接:子包的 node_modules 仅包含直接依赖,通过符号链接引用全局存储中的实际文件,避免依赖冗余。
-
严格隔离:默认启用严格模式,防止跨包访问未声明的“幽灵依赖”
2. 配置文件
-
pnpm-workspace.yaml
:这是 pnpm workspace 的核心配置文件,必须放在项目根目录下。它定义了哪些目录下的包属于 workspace。例如:yamlpackages: - 'packages/*' - 'apps/*'
这表示
packages/
和apps/
目录下的所有直接子目录都被视为 workspace 的一部分。 -
package.json
:根目录下的package.json
可以设置为"private": true
,以避免误将整个 workspace 发布到 npm 仓库。
3. 依赖管理
- 本地链接:当
linkWorkspacePackages
设置为true
时,pnpm 会优先从 workspace 中链接满足依赖范围的包。例如,如果bar
依赖"foo": "^1.0.0"
,且foo@1.0.0
存在于 workspace 中,则会直接链接foo@1.0.0
到bar
。 workspace:
协议:使用workspace:
协议可以强制 pnpm 只从本地 workspace 中解析依赖。例如:json{ "dependencies": { "foo": "workspace:*" } }
foo
的版本必须来自 workspace,且版本号由 workspace 中的包决定。
4. 依赖提升(Hoisting)
pnpm 会将公共依赖提升到根目录的 node_modules
中,避免重复安装,节省磁盘空间并提高安装速度。
5. 脚本运行
可以使用 pnpm -r run <script>
命令递归运行所有 workspace 中的脚本。例如:
bash
pnpm -r run build
这将运行所有 workspace 中的 build
脚本。
6. 循环依赖
如果 workspace 中存在循环依赖,pnpm 无法保证脚本按拓扑顺序运行,并会发出警告。
实例说明
1. 项目结构
假设我们有一个项目结构如下:
my-monorepo/
├── package.json
├── pnpm-workspace.yaml
├── apps/
│ └── web/
├── packages/
│ ├── ui/
│ └── shared-utils/
2. 配置文件
pnpm-workspace.yaml
:yamlpackages: - 'apps/*' - 'packages/*'
- 根目录
package.json
:json{ "name": "my-monorepo", "private": true, "scripts": { "build": "pnpm -r run build" } }
3. 安装依赖
在根目录运行以下命令安装所有依赖:
bash
pnpm install
4. 添加依赖
- 为整个 workspace 添加依赖:bash
pnpm add <package-name> -w
- 为特定 workspace 添加依赖:bash
pnpm add <package-name> --filter <workspace-name>
5. 运行脚本
- 运行特定 workspace 的脚本:bash
pnpm run <script-name> --filter <workspace-name>
- 运行所有 workspace 的脚本:bash
pnpm -r run <script-name>
6. 子包互相引用
假设 web
依赖于 ui
和 shared-utils
,可以在 web/package.json
中这样声明:
json
{
"name": "web",
"dependencies": {
"ui": "workspace:*",
"shared-utils": "workspace:*"
}
}
然后运行以下命令安装依赖:
bash
pnpm install --filter web
通过以上配置和操作,pnpm workspace 可以高效地管理多个包的依赖关系,简化开发流程。