PNPM 是现代 Node 包管理器,Monorepo 是「单仓库多包」的工程架构;
pnpm-workspace.yaml是 PNPM Monorepo 的核心配置文件。workspace:*用于引用仓库内本地源码包;catalog是 PNPM9+ 专属全局版本池,统一所有子应用第三方依赖版本。本文包含基础理论、配置详解、常用命令、踩坑经验,可日常查阅。
一、基础概念区分
1. Monorepo 是什么
Monorepo 是代码仓库组织架构:一个 Git 仓库,同时维护多个独立 package 包。 包可以是:公共工具库、组件库、前端业务应用。
- 优势:
- 内部包修改实时生效,无需打包发布到 npm
- 统一代码规范、CI 流水线、版本管理
- 内部包之间互相依赖,本地调试非常方便
注意:Monorepo ≠ PNPM。Monorepo 是工程思想;pnpm/yarn/npm 是包管理器,都可以实现 monorepo。
2. PNPM 是什么
PNPM 是 Node 的包管理器,对比 npm/yarn:
- 全局硬链接存储,相同包只下载一次,节省磁盘空间
- 依赖扁平化策略更严格,幽灵依赖问题更少
- 原生内置 Workspace 能力,对 monorepo 项目友好
- PNPM9 新增
catalog版本池,专门优化多子包场景下的依赖版本统一管理
3. pnpm-workspace.yaml
monorepo 项目核心配置文件,必须放在仓库根目录。 作用:告诉 pnpm 两件核心事:
- 哪些目录属于当前 workspace 工作区(哪些文件夹算作子包)
- 【可选】catalog 版本池,统一管理第三方 npm 包版本
二、pnpm-workspace.yaml 完整配置说明
最小可用模板
# pnpm-workspace.yaml
packages:
- 'packages/*' # packages 下一级目录全部纳入workspace(存放公共源码包)
- 'apps/*' # apps 下一级目录全部纳入workspace(存放前端应用)
# catalog:默认版本池,pnpm9+专属,统一第三方依赖版本
catalog:
"@tanstack/vue-query": "^5.59.0"
dayjs: "^1.11.13"
# 多版本池子(可选,同一个包维护多套版本)
# catalogs:
# vue34:
# vue: "^3.4.30"
# vue35:
# vue: "^3.5.8"
# 可选配置项
disallowWorkspaceCycles: true # 禁止循环依赖,出现循环依赖直接install报错
saveWorkspaceProtocol: rolling # 添加本地workspace包依赖时,自动写入 workspace:*
includeWorkspaceRoot: false # 递归执行命令,默认不在根包执行
1. packages 字段详解(glob 通配符)
packages 使用 glob 匹配规则:匹配到的目录,只要包含 package.json,就会被识别为 workspace 子包,子包之间可以使用 workspace:* 协议互相引用。
表格
| glob 写法 | 含义 |
|---|---|
packages/* | 匹配 packages 下一级子文件夹,不会递归深层目录 |
apps/** | 递归匹配 apps 下所有层级目录(多层嵌套) |
!**/test/** | ! 代表排除,所有 test 目录下的包不纳入 workspace |
只有被 packages 匹配到的目录,才能使用
workspace:*协议;不在列表中的目录,无法引用本地源码包。
2. workspace:* 协议
// apps/app-one/package.json
"@common/design": "workspace:*"
- 归属:pnpm/yarn/npm 均支持,属于 monorepo 通用约定
- 含义:不要去 npm 远程仓库下载,直接引用当前 workspace 内本地源码包,pnpm 创建软链接。
*:直接匹配本地包当前版本,不做版本号校验。- 使用场景:仓库内部公共源码包,放在
packages目录下。
适用:仓库内部源码包;业务第三方 npm 包不要使用
workspace:*。
3. catalog 版本池(pnpm 9+ 专属)
# pnpm-workspace.yaml根配置
catalog:
dayjs: "^1.11.13"
子应用 package.json 中:
"dayjs": "catalog:"
- 归属:PNPM 独有,yarn/npm 不识别该语法。
- 含义:版本号从根目录 catalog 池读取,所有子包共用同一个版本。
- 优势:升级依赖,只修改 yaml 一处,不用修改 apps、packages 下大量 package.json。
⚠️ 规范:业务新增第三方包不要加到 catalog。catalog 适合框架底层公共依赖维护,业务组件直接写固定版本号。
三、依赖安装两种模式
区分:安装到子应用 vs 安装到workspace 根目录
方式 1:安装到子应用(推荐:仅单个 app 使用的依赖)
场景:依赖只在 apps/app-one 使用,其它子应用不需要,例如拖拽分割面板组件
# 进入子应用目录
cd apps/app-one
# 安装依赖,写入 apps/app-one/package.json
pnpm add vue-splitpanes
特点:
- 依赖隔离,其它子应用打包不会包含这个包
- 删除该子应用时,依赖同步清理,无冗余
- 不改动根 package.json,不改动 pnpm-workspace.yaml
方式 2:安装到 workspace 根目录(-w 参数)
场景:多个子应用(app-one、app-two)都要复用这个依赖
# 在项目仓库根目录执行(和pnpm-workspace.yaml同级)
pnpm add vue-splitpanes -w
-w = --workspace-root,依赖写入仓库根package.json特点:
- 全仓库所有子包都可以 import,仓库内只保留一份依赖
- 缺点:所有子应用打包都会带上该包,增大不需要该包的应用打包体积
- 卸载:根目录执行
pnpm remove vue-splitpanes -w
四、PNPM Workspace 高频常用命令
全部在仓库根目录执行
1. 查看所有 workspace 子包
pnpm ls -r
2. 递归所有子包执行命令 -r / --recursive
# 所有子包install
pnpm -r install
# 所有子包执行build构建
pnpm -r build
3. filter:筛选指定子包执行(高频)
# 只对 app-one 执行 build
pnpm --filter app-one build
# 只对 app-one 执行安装依赖
pnpm --filter app-one add xxx
4. 新增 / 删除依赖
# 根安装
pnpm add xxx -w
# 根卸载
pnpm remove xxx -w
# 子包安装(先cd进apps/app-one)
pnpm add xxx
pnpm remove xxx
5. 查看 workspace 依赖树
pnpm ls
五、概念对比表(快速查阅)
表格
| 标识 / 配置 | 提供方 | 作用 | 使用场景 |
|---|---|---|---|
workspace:* | pnpm/yarn/npm 均支持 | 引用仓库本地源码包,软链接,不从 npm 下载 | 仓库内部 packages 公共源码包 |
catalog: | pnpm9 + 独有 | 统一第三方 npm 包版本,版本定义在 pnpm-workspace.yaml | 底层公共第三方依赖,业务新增包不要用 |
| 根 package.json | pnpm | 存放全仓库共享依赖 | 多个子应用共用的包,使用pnpm add -w |
| 子应用 package.json | pnpm | 存放当前 app 私有依赖 | 仅单个应用使用的业务组件、第三方库 |
六、实战经验 & 避坑
- 不要手动修改 catalog:catalog 用于底层公共依赖管理,业务新增第三方包直接在子应用
pnpm add,写固定版本号,不要写catalog:。 workspace:*只用于本地 packages 源码包,不要用来引用 npm 远程包。- packages 数组不要随意修改:删除
apps/*会导致所有 app 脱离 workspace,workspace:*全部失效。 - 依赖安装原则:哪个 app 用,就装到哪个 app;只有多 app 共用,才放到根目录使用
-w。 - 循环依赖:
disallowWorkspaceCycles: true开启后,A 依赖 B,B 依赖 A,pnpm install直接报错,需要重构代码。 - 包导入路径:子包内部使用
@别名,是子应用内 tsconfig/vite 配置,不是 pnpm workspace 能力。 - 安装第三方 UI 组件,记得手动引入组件 css,否则组件无样式。
七、FAQ
Q1:monorepo 和 pnpm 是一回事吗?
A:不是。Monorepo 是仓库架构;pnpm 是包管理器。pnpm 的 workspace 是 pnpm 实现 monorepo 的一套能力。
Q2:catalog 是不是必须要用?
A:不是,catalog 是 pnpm9 的增强特性,monorepo 项目完全可以不使用,每个子 package.json 写独立版本号。catalog 只是用来简化多包项目的版本维护。
Q3:pnpm add -w 安装的包,可以在子应用直接 import 吗?
A:可以。所有 workspace 下的子包都能导入根 package.json 里的依赖。代价是其它子应用打包也会包含该依赖。
Q4:新增自定义业务 Vue 组件,放在哪里?
A:业务组件源码放在子应用内部,例如 apps/app-one/src/components/biz,不属于 pnpm package,不需要在 pnpm-workspace.yaml 注册,只是普通 vue 文件。
Q5:升级仓库公共包,会不会影响 workspace 配置?
A:升级 packages 内公共源码包,一般不会改动pnpm-workspace.yaml,自己新增的业务依赖不受影响。
转载自 CSDN-专业IT技术社区



