在使用 pnpm 的 monorepo 项目时,你可能见过这样的写法:
{
"dependencies": {
"@my-org/ui": "workspace:*"
}
}
很多初学者都会疑惑:
workspace:是什么?- 不写它行不行?
- 它和版本号有什么关系?
这篇文章会用最直观、最少前置知识的方式,带你一次搞懂 pnpm workspace 协议的原理和使用。
一、先说结论(一句话版本)
workspace:协议的作用是:
强制 pnpm 使用当前 workspace 里的本地包,而不是去 npm 仓库下载。
它解决的不是“版本问题”,而是一个更基础的问题:
👉 这个依赖“从哪来”?
二、没有 workspace: 会发生什么?
先看一个最常见的 monorepo 结构:
packages/
ui (name: @my-org/ui)
apps/
web
在 apps/web/package.json 中写:
{
"dependencies": {
"@my-org/ui": "^1.0.0"
}
}
这时 pnpm 的行为是:
- 在 workspace 中查找
@my-org/ui - 如果本地存在,并且版本满足
^1.0.0 - 👉 默认使用本地包
也就是说:
即使你不写
workspace:,pnpm 也“通常”会用本地包
那问题来了——
既然这样,workspace: 有什么用?
三、workspace: 到底解决了什么问题?
1️⃣ 明确表达“这是一个本地依赖”
当你写:
{
"@my-org/ui": "workspace:*"
}
你是在向 pnpm 明确声明一件事:
这个依赖必须来自当前 workspace,本地没有就直接报错。
它的意义不是“让 pnpm 能用本地包”,
而是 防止 pnpm 用错包。
2️⃣ 防止“误用远程同名包”
假设有一天:
- 你的 workspace 里还没有
@my-org/ui - 但 npm 仓库里刚好有一个同名包
如果你写的是:
"@my-org/ui": "^1.0.0"
pnpm 会:
👉 去 npm 仓库下载那个包
但如果你写的是:
"@my-org/ui": "workspace:*"
pnpm 会直接:
❌ 报错:workspace 中不存在该包
👉 这就是 workspace: 的安全价值
四、workspace 协议的“真实原理”(人话版)
pnpm 在安装依赖时,会先把每个依赖解析成一种“类型”:
- 普通 semver(
^1.0.0) - workspace 协议
- file / git / link 等
当 pnpm 看到:
"@my-org/ui": "workspace:*"
它内部会把这个依赖标记为:
“只能从 workspace Package Map 中解析”
接下来的规则非常简单:
- ✅ workspace 里有 → 用本地包
- ❌ workspace 里没有 → 直接失败
- 🚫 不会查 npm registry
所以可以这样理解:
workspace: 是一种“来源锁定协议”
五、workspace:* / workspace:^ / workspace:~ 有什么区别?
这是很多人第一次看到会懵的地方。
结论先给出来:
它们在“安装阶段没有区别”,
区别只体现在“发布阶段”。
1️⃣ 安装阶段(最重要的阶段)
无论你写:
workspace:*
workspace:^
workspace:~
pnpm 都会:
- 忽略版本判断
- 直接使用本地包
👉 安装行为完全一致
2️⃣ 发布阶段(publish 到 npm 时)
workspace 协议 不会被发布,而是会被替换:
假设本地包版本是 1.2.3
| 写法 | 发布后 |
|---|---|
| workspace:* | ^1.2.3 |
| workspace:^ | ^1.2.3 |
| workspace:~ | ~1.2.3 |
所以:
workspace 后面的符号,
本质是在帮你决定将来别人怎么依赖你。
六、什么时候“应该”用 workspace:?
✅ 推荐使用的场景
- monorepo 内部包互相依赖
- 希望明确表达“这是内部依赖”
- 不希望误用远程同名包
- 希望发布时自动生成合理版本号
👉 团队项目 / 长期维护项目:强烈推荐
❌ 可以不写的场景
- 个人实验项目
- 确定不会 publish
- 对依赖来源不敏感
👉 即使不写,pnpm 多数时候也能正常工作
但不写等于放弃了一层安全约束
七、一个完整示例
packages/ui/package.json
{
"name": "@my-org/ui",
"version": "1.0.0"
}
apps/web/package.json
{
"dependencies": {
"@my-org/ui": "workspace:*"
}
}
pnpm 的理解是:
@my-org/ui必须来自当前 workspace,
安装时用本地包,
发布时替换成真实版本号。
八、总结
workspace:协议不是版本控制工具,而是依赖来源控制工具。
它的作用是明确告诉 pnpm:
“这个依赖只能来自当前 workspace,而不是外部仓库。”