注册源

添加于:v11.23.0

pnpm-workspace.yaml 中的 registries 设置声明了项目每个安装来源的注册源 — 只需声明一次,并以注册源的 URL 为键。关于某个注册源,pnpm 所知的一切都保存在其条目中:路由到它的作用域、它响应的裸说明符前缀,以及它背后服务器的状况。

pnpm-workspace.yaml
registries:
  https://npm.corp.example.com/:
    serverType: artifactory
    scopes: ["@acme", "@corp-tools"]
    prefix: work
  https://verdaccio.corp.example.com/:
    scopes: ["@"]
    supportsTimeField: true

URL 之所以是键,是因为条目中的每个事实都是关于该服务器的事实。如果 tarball 布局改为以作用域为键,它就会绑定到该作用域当前指向的对象,而两名开发者如果作用域解析结果不同,就会写出对哪些 URL 可以省略存在分歧的锁文件。

条目可以包含:

字段 类型 它声明了什么
scopes string[] 路由到此注册源的包作用域。
prefix string 此注册源所响应的裸说明符前缀。
serverType string 服务器如何组织 tarball URL:npm 或 artifactory。
supportsTimeField boolean 服务器的简化元数据是否带有 time 字段。

其他任何字段都会被拒绝。尤其要注意,凭据(_authToken、_auth、_password、username、tokenHelper)和 TLS 材料(ca、cafile、cert、certfile、key、keyfile)会被拒绝,而不是被静默忽略 — pnpm-workspace.yaml 会被提交到仓库,因此它们应放在 .npmrc 中(例如 //npm.corp.example.com/:_authToken=...)。出于同样原因,内嵌 user:pass@ 凭据的 URL 键会被拒绝。

将包路由到注册源#

scopes#

其包从此注册源解析的作用域,需以 @ 为前缀。单独的 "@" 会路由无作用域的默认注册源 — 也就是 registry 设置所指定的那个注册源:

pnpm-workspace.yaml
registries:
  https://npm.corp.example.com/:
    scopes: ["@acme"]
  https://registry.internal.example.com/:
    scopes: ["@"]

一个作用域只能解析到一个注册源,因此从两个条目路由同一作用域是错误的。

prefix#

此注册源所响应的命名注册源前缀,例如 "lib": "work:^2.0.0":

pnpm-workspace.yaml
registries:
  https://npm.work.example.com/:
    prefix: work
pnpm add work:@corp/lib@^2.0.0

每个条目最多声明一个前缀,且两个条目不能声明相同的前缀:前缀是注册源在锁文件包键(foo@work:1.0.0)中的身份,因此第二种写法会把来自同一注册源的同一个包键控两次。

在此声明的前缀遵循与它们所取代的已废弃 namedRegistries 设置相同的规则:内置的 gh: 和 npmjs: 别名可以通过在你自己的 URL 上声明其前缀来覆盖,保留名称会被拒绝,而通过前缀解析的包会获得带注册源限定的锁文件键。

描述服务器#

serverType#

并非所有注册源都像 npm 注册源那样组织 tarball URL。当 pnpm 能根据包的名称、版本和注册源重建 tarball URL 时,它会从 pnpm-lock.yaml 中省略该 URL — 这样锁文件中就不会带有该包的特定主机 URL,重命名或迁移注册源也不会引起锁文件的变动。至于 pnpm 能否重建 URL,取决于服务器,而 serverType 就是你声明它的位置。它有三种状态:

serverType 含义
未声明 严格:只有当 tarball URL 恰好是规范的 npm 布局 URL(<registry>/<name>/-/<scopeless-name>-<version>.tgz)时,才会将其省略。除 registry.npmjs.org 之外的每个注册源,默认都按这种方式读取。
npm 该服务器的行为与 registry.npmjs.org 相同,它既会从百分号编码的路径(/@acme%2Fwidget/...)提供带作用域的包,也会从未编码的路径提供。公共注册源的忠实镜像或缓存代理就是这种。这是为 registry.npmjs.org 本身内置的。
artifactory 该服务器会在带作用域的包的 tarball 文件名中重复作用域:@acme/widget/-/@acme/widget-1.0.0.tgz,而 npm 布局会将其去掉(@acme/widget/-/widget-1.0.0.tgz)。

对于 JFrog Artifactory 注册源,这决定了最终是得到一个为每个带作用域的包都记录特定主机 tarball URL 的锁文件,还是得到一个完全不记录此类 URL 的锁文件:

pnpm-workspace.yaml
registries:
  https://acme.jfrog.example.com/artifactory/api/npm/npm-virtual/:
    serverType: artifactory
    scopes: ["@acme"]

常见服务器的取值:

服务器 serverType
JFrog Artifactory artifactory
GitLab 软件包注册源 artifactory — 它使用相同的布局,在文件名中重复作用域。
npm 注册源的忠实镜像或缓存代理 npm
Verdaccio, Sonatype Nexus, Azure Artifacts 无需设置 — 它们提供的正是规范的 npm 布局,严格默认值已能重建。
GitHub Packages 无需设置 — 其下载 URL 含有无法从包身份推导的内容摘要,因此它们会被保留在锁文件中。

布局是声明的,而不是推断出来的:虚拟仓库可以同时提供两种布局,具体取决于每个包是从上游同步而来还是在本地发布,因此不存在 pnpm 可以探测的注册源级信号。声明它还能让错误的值成为可修复的配置错误,而不是悄无声息的故障。

注意

serverType 是关于服务器的声明,只有其运营者才能做出,而锁文件依赖它:被省略的 tarball URL 会在每次安装时按声明的布局重建,包括 --frozen-lockfile 安装。请声明服务器实际提供的布局,并预期在声明后出现一次性的锁文件差异 — pnpm 现在能够重建的 URL 会在下一次写入锁文件的安装中从锁文件中消失。

supportsTimeField#

此注册源的简化元数据是否带有 time 字段。而 registry.npmjs.org 则不是这样,这正是默认值为 false 的原因,也是诸如 minimumReleaseAge 这类基于时间的解析特性会退回到大得多的完整元数据文档的原因。确实带有该字段的注册源——Verdaccio v5.15.1+ 以及若干代理——值得声明:

pnpm-workspace.yaml
registries:
  https://verdaccio.corp.example.com/:
    scopes: ["@"]
    supportsTimeField: true

这是 registrySupportsTimeField 设置的按注册源形式。回退行为按注册源分别决定:某个需要完整元数据的注册源不再让其他注册源也付出代价,而对于项目未描述的每个注册源,registrySupportsTimeField 仍是答案。

该设置可放在哪里#

该设置应放在 pnpm-workspace.yaml 中,而不是 .npmrc 或全局配置中,因为锁文件依赖它:如果一名开发者省略了 tarball URL,而另一名开发者以不同方式重建它,就会破坏冻结安装。

全局配置文件(config.yaml)可以声明路由 — scopes 和 prefix — 从而使某个作用域或诸如 work: 这样的别名适用于机器上的每个项目。服务器描述(serverType 和 supportsTimeField)只从 pnpm-workspace.yaml 读取,原因同上。

未声明任何路由的条目描述的是在别处配置的注册源 — 例如在 .npmrc 中设置的默认注册源。此类条目仅当其 URL 是项目实际解析所用的 URL 时才生效;pnpm 会对不匹配任何已配置注册源的条目发出警告,因为否则它们会闲置在那里不起作用(例如过期的 URL、已迁移的作用域)。

该设置 URL 键中的环境变量不会被展开,原因与它们在 pnpm-workspace.yaml 中其他注册源 URL里不被展开相同:该文件会被提交,而把环境变量展开进请求目标可能会将机密泄露给由攻击者控制的主机。包含 ${...} 占位符的键会被忽略。

旧的结构#

在 v11.23.0 之前,registries 将作用域映射到 URL,并用 default 键命名主注册源:

pnpm-workspace.yaml
registries:
  default: https://registry.npmjs.org/
  "@acme": https://npm.corp.example.com/

这种结构仍被接受,行为与之前相同。两种结构不能混用在同一个映射中 — 值为字符串的条目是作用域路由,而以 URL 为键的作用域路由则是错误。

设置 namedRegistries 已废弃,改用 prefix。它仍会被读取,但仅用于 registries 未声明的前缀;当两者都声明了前缀时,pnpm 会发出警告。