◆

pnpm-workspace.yaml packages 通配符配置详解

2023-03-03 01:220

pnpm-workspace.yaml 配置安装问题

配置示例

packages:
  - 'common'
  - 'common/*'
  - 'common/*/*'
  - 'common/**'
  • common: common/package.json 的包会安装,底下的任何子目录都不会安装
  • common/*: common 下第一级子目录包会安装,子目录下的任何子目录不会安装,其本身下的 common/package.json 也不会安装
  • common/*/*: common 下第二级子目录包会安装,其他任何不安装
  • common/**: common 下所有 package.json 被安装,包含其本身

为什么会有这些差别

我一开始也觉得奇怪:common 和 common/* 看着差不多,为什么一个装本体不装子目录,另一个反过来?搞清楚一点就通了——packages 里写的每一项都是目录的 glob 匹配模式,不是「以这个目录为根往下递归找」。pnpm 拿这些模式去匹配仓库里的目录路径,凡是被命中的目录,如果里面有 package.json,就登记成一个 workspace package。

按 glob 的语义再看这四条就很直白:

  • common 只能匹配到 common 这一个路径本身,所以只有 common/package.json 被登记。
  • * 匹配一层路径片段且不跨越 /,所以 common/* 匹配 common/utils、common/ui,但匹配不到 common 自己,也匹配不到 common/ui/theme。
  • common/*/* 同理,只命中恰好两层深的目录。
  • ** 是跨层匹配,common/** 命中 common 以及它下面任意深度的目录,所以是「全都要」。

因为是逐条求并集,想同时要本体和所有子包,最省事的写法就是直接 common/**;要是只想要本体加第一级,写两条 common 和 common/* 就行。

排除某些目录

glob 前面加 ! 表示排除,这在 monorepo 里比通配符本身更常用。比如仓库里有一堆测试固件目录也带 package.json,不想被当成工作区包:

packages:
  - 'packages/**'
  # 排除所有 test 目录下的包
  - '!**/test/**'
  # 排除历史归档
  - '!packages/legacy/**'

排除项和包含项没有顺序要求,pnpm 会先把包含项匹配出来的集合算好,再把排除项命中的剔掉。所以 ! 那几行放前面放后面都一样。

几个容易踩的坑

node_modules 里的包不会被匹配。 这个不用自己写排除规则,pnpm 内部就跳过了,不然依赖里那几千个 package.json 全都成工作区包了。

改完 pnpm-workspace.yaml 必须重新 pnpm install。 工作区成员列表是在 install 阶段解析并写进 pnpm-lock.yaml 的 importers 段的,光改 yaml 不装,pnpm -r 之类的递归命令还是按老的列表走。我调整完通配符之后如果发现某个新包死活不被识别,第一反应就是回去补一次 install。

pnpm-workspace.yaml 必须在仓库根目录,且文件名不能写成 .yml。 pnpm 是从当前目录往上找这个精确文件名来确定工作区根的,写成 pnpm-workspace.yml 会被完全忽略,表现就是所有 -w、--filter 相关的命令都报「不在工作区里」。

包名和目录名是两件事。 --filter 过滤的是 package.json 里的 name 字段,不是目录名。所以 common/ui 目录里如果写的是 "name": "@app/ui",过滤时要用 pnpm --filter @app/ui build。

验证匹配结果

改完配置我一般不靠猜,直接列一下 pnpm 实际认到了哪些包:

# 列出当前工作区所有包(名称 + 版本 + 路径)
pnpm list -r --depth -1

# 只看包名,确认数量对不对
pnpm list -r --depth -1 --json | grep '"name"'

--depth -1 的意思是不展开任何依赖树,只输出包本体信息,正好用来核对工作区成员。如果输出里少了你期望的包,就是通配符层级没对上;如果多了不该有的,就补一条 ! 排除。

💬留言板0

还没有留言,来发表第一条吧~

PAGE LOAD / LIVEpnpm-workspace.yaml packages 通配符配置详解加载中