5月28日 02:10

pnpm workspace 如何配置和使用?

pnpm workspace 是 pnpm 内置的 monorepo 方案,让你在一个仓库里管理多个互相依赖的包。相比 yarn workspaces 和 lerna,它零额外依赖、硬链接共享磁盘空间,配置也最简单。

如何声明 workspace

在项目根目录创建 pnpm-workspace.yaml

yaml
packages: - 'packages/*' - 'apps/*' - 'shared/*'

根目录的 package.json 必须设置 "private": true,防止根包被误发布。

典型目录结构

shell
my-monorepo/ ├── pnpm-workspace.yaml ├── package.json # private: true ├── pnpm-lock.yaml ├── .npmrc # pnpm 专用配置 ├── packages/ │ ├── ui/ │ │ ├── package.json # name: @my-org/ui │ │ └── src/ │ └── utils/ │ ├── package.json # name: @my-org/utils │ └── src/ └── apps/ ├── web/ │ ├── package.json # name: @my-org/web │ └── src/ └── server/ ├── package.json └── src/

包间依赖如何引用

使用 workspace: 协议引用本地包,开发时直接链接源码,不用发布再安装:

json
// apps/web/package.json { "name": "@my-org/web", "dependencies": { "@my-org/ui": "workspace:*", "@my-org/utils": "workspace:^1.0.0" } }

workspace: 后面的版本写法决定了发布时的替换规则:

协议写法开发时行为发布时替换为
workspace:*链接最新精确版本如 1.2.3
workspace:^链接最新^1.2.3
workspace:~链接最新~1.2.3
workspace:^1.0.0链接最新^1.0.0(保留原范围)

发布时 workspace: 会被自动替换为实际版本号,这是 pnpm 的内置行为,不需要额外配置。

常用命令速查

bash
# 安装所有包的依赖 pnpm install # 在指定包中执行命令(--filter 或 -F) pnpm --filter @my-org/ui build pnpm -F @my-org/ui build # 递归执行:所有包都跑 build pnpm -r build # 只构建有变更的包(基于 git diff) pnpm -r --filter "...[origin/main]" build # 给指定包添加依赖 pnpm --filter @my-org/web add @my-org/ui # 给根目录添加公共开发依赖(-w 标志) pnpm add -Dw eslint prettier

-r(递归)和 --filter 的区别:-r 对所有包执行,--filter 按条件筛选。生产环境推荐用 --filter 精确控制,避免无关包被意外构建。

.npmrc 关键配置

pnpm workspace 的许多行为可以通过 .npmrc 调整:

ini
# 未在 workspace 找到的包是否从 registry 下载(默认 true) link-workspace-packages=true # 依赖提升策略(避免幽灵依赖) shamefully-hoist=false node-linker=hoisted # 需要 hoist 时用这个,不推荐 # 严格对等依赖 strict-peer-dependencies=true

link-workspace-packages=true 配合 workspace:* 使用时,如果本地包版本满足范围就链接本地,否则从 registry 下载。这在逐步迁移 monorepo 时很有用。

用 changesets 管理版本和发布

多包版本管理推荐用 changesets,它是 pnpm 官方推荐的方案:

bash
# 安装 pnpm add -Dw @changesets/cli pnpm changeset init # 工作流 pnpm changeset # 交互式记录本次变更(选包、选版本类型、写 changelog) pnpm changeset version # 根据记录更新 package.json 和 CHANGELOG.md pnpm -r publish # 发布所有有新版本的包

changeset init 会生成 .changeset/ 目录和 config.json,其中可以配置 changelog 格式、access(public/restricted)等。

常见问题

Q: 修改了子包代码,依赖它的包要重新安装吗?

不需要。workspace:* 链接的是源码,修改即生效(前提是需要重新 build 的包要重新构建)。

Q: 发布时 workspace: 协议怎么处理?

pnpm publishworkspace:* 会自动替换为 package.json 中的实际版本号。如果版本号不存在会报错。

Q: 怎么排查某个包的依赖关系?

bash
pnpm list --filter @my-org/web --depth 1 # 查看依赖树 pnpm why @my-org/ui --filter @my-org/web # 查看为什么依赖这个包

Q: 子包之间循环依赖怎么办?

pnpm 会报错。解决方式是抽取共享逻辑到第三个包,或者通过接口/事件解耦。

pnpm workspace vs 其他方案

特性pnpm workspaceYarn WorkspacesLernaTurborepo
内置支持需安装需安装
依赖存储硬链接(全局 store)符号链接各自安装依赖 pnpm/yarn
磁盘效率最高中等最低取决于底层
任务缓存
配置复杂度
版本管理需配合 changesets需配合工具内置需配合工具

pnpm workspace 本身只解决依赖管理和包链接,任务编排(缓存、并行)交给 Turborepo 或 Nx,版本发布交给 changesets——这是目前最主流的组合方案。

标签:PNPM