208 lines
3.8 KiB
Markdown
208 lines
3.8 KiB
Markdown
---
|
||
|
||
name: pnpm-workspaces
|
||
description: 通过工作空间实现 monorepo 支持,用于管理多个包
|
||
|
||
---
|
||
|
||
# pnpm Workspaces
|
||
|
||
pnpm 通过工作空间(workspaces)内置支持 monorepo(多包仓库)。
|
||
|
||
## 设置工作空间
|
||
|
||
在仓库根目录创建 `pnpm-workspace.yaml`:
|
||
|
||
```yaml
|
||
packages:
|
||
# 包含 packages/ 目录下的所有包
|
||
- 'packages/*'
|
||
# 包含所有应用
|
||
- 'apps/*'
|
||
# 包含嵌套的包
|
||
- 'tools/*/packages/*'
|
||
# 排除测试目录
|
||
- '!**/test/**'
|
||
```
|
||
|
||
## 工作空间协议
|
||
|
||
使用 `workspace:` 协议引用本地包:
|
||
|
||
```json
|
||
{
|
||
"dependencies": {
|
||
"@myorg/utils": "workspace:*",
|
||
"@myorg/core": "workspace:^",
|
||
"@myorg/types": "workspace:~"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 协议变体
|
||
|
||
| 协议 | 行为 | 发布时转换 |
|
||
|----------|----------|--------------|
|
||
| `workspace:*` | 任意版本 | 实际版本(如 `1.2.3`) |
|
||
| `workspace:^` | 兼容版本 | `^1.2.3` |
|
||
| `workspace:~` | 补丁版本 | `~1.2.3` |
|
||
| `workspace:^1.0.0` | Semver 范围 | `^1.0.0` |
|
||
|
||
## 过滤包
|
||
|
||
使用 `--filter` 在特定包上运行命令:
|
||
|
||
```bash
|
||
# 按包名
|
||
pnpm --filter @myorg/app build
|
||
pnpm -F @myorg/app build
|
||
|
||
# 按目录路径
|
||
pnpm --filter "./packages/core" test
|
||
|
||
# Glob 模式
|
||
pnpm --filter "@myorg/*" lint
|
||
pnpm --filter "!@myorg/internal-*" publish
|
||
|
||
# 所有包
|
||
pnpm -r build
|
||
pnpm --recursive build
|
||
```
|
||
|
||
### 基于依赖关系的过滤
|
||
|
||
```bash
|
||
# 包及其所有依赖
|
||
pnpm --filter "...@myorg/app" build
|
||
|
||
# 包及其所有依赖者
|
||
pnpm --filter "@myorg/core..." test
|
||
|
||
# 双向
|
||
pnpm --filter "...@myorg/shared..." build
|
||
|
||
# 自 git 引用以来的变更
|
||
pnpm --filter "...[origin/main]" test
|
||
pnpm --filter "[HEAD~5]" lint
|
||
```
|
||
|
||
## 工作空间命令
|
||
|
||
### 安装依赖
|
||
```bash
|
||
# 安装所有工作空间包
|
||
pnpm install
|
||
|
||
# 向特定包添加依赖
|
||
pnpm --filter @myorg/app add lodash
|
||
|
||
# 添加工作空间依赖
|
||
pnpm --filter @myorg/app add @myorg/utils
|
||
```
|
||
|
||
### 运行脚本
|
||
```bash
|
||
# 在所有包含该脚本的包中运行
|
||
pnpm -r run build
|
||
|
||
# 按拓扑顺序运行(依赖优先)
|
||
pnpm -r --workspace-concurrency=1 run build
|
||
|
||
# 并行运行
|
||
pnpm -r --parallel run test
|
||
|
||
# 流式输出
|
||
pnpm -r --stream run dev
|
||
```
|
||
|
||
### 执行命令
|
||
```bash
|
||
# 在所有包中运行命令
|
||
pnpm -r exec pwd
|
||
|
||
# 在特定包中运行
|
||
pnpm --filter "./packages/**" exec rm -rf dist
|
||
```
|
||
|
||
## 工作空间设置
|
||
|
||
在 `.npmrc` 或 `pnpm-workspace.yaml` 中配置:
|
||
|
||
```ini
|
||
# 自动链接工作空间包
|
||
link-workspace-packages=true
|
||
|
||
# 优先使用工作空间包而非注册表
|
||
prefer-workspace-packages=true
|
||
|
||
# 单一锁文件(推荐)
|
||
shared-workspace-lockfile=true
|
||
|
||
# 工作空间协议处理方式
|
||
save-workspace-protocol=rolling
|
||
|
||
# 并发工作空间脚本数
|
||
workspace-concurrency=4
|
||
```
|
||
|
||
## 发布工作空间
|
||
|
||
发布时,`workspace:` 协议会被转换:
|
||
|
||
```json
|
||
// 发布前
|
||
{
|
||
"dependencies": {
|
||
"@myorg/utils": "workspace:^"
|
||
}
|
||
}
|
||
|
||
// 发布后
|
||
{
|
||
"dependencies": {
|
||
"@myorg/utils": "^1.2.3"
|
||
}
|
||
}
|
||
```
|
||
|
||
从 CI 发布时使用 `--no-git-checks`:
|
||
```bash
|
||
pnpm publish -r --no-git-checks
|
||
```
|
||
|
||
## 最佳实践
|
||
|
||
1. **对内部依赖使用 workspace 协议**
|
||
2. **启用 `link-workspace-packages`** 以实现自动链接
|
||
3. **使用共享锁文件** 以保证一致性
|
||
4. **构建时按依赖过滤** 以确保正确的顺序
|
||
5. **使用目录(catalogs)** 管理共享的外部依赖版本
|
||
|
||
## 项目结构示例
|
||
|
||
```
|
||
my-monorepo/
|
||
├── pnpm-workspace.yaml
|
||
├── package.json
|
||
├── pnpm-lock.yaml
|
||
├── packages/
|
||
│ ├── core/
|
||
│ │ └── package.json
|
||
│ ├── utils/
|
||
│ │ └── package.json
|
||
│ └── types/
|
||
│ └── package.json
|
||
└── apps/
|
||
├── web/
|
||
│ └── package.json
|
||
└── api/
|
||
└── package.json
|
||
```
|
||
|
||
<!--
|
||
参考来源:
|
||
- https://pnpm.io/workspaces
|
||
- https://pnpm.io/filtering
|
||
- https://pnpm.io/npmrc#workspace-settings
|
||
-->
|