pnpm 12 有什么不同
pnpm 12 是 Rust 中 pnpm 的重写版本,目前是 发布候选版本。 升级并非“迁移”:除了下文列出的差异外,它保留了 pnpm 11 的命令、选项、配置和锁文件格式,且文档适用于这两个版本。
有五处不同,其中一处——即被移除的标志——是彻底失效,而非表现出不同的行为。 这篇文章将它们汇总在了一起。
项目感知的全局二进制
全局安装的 node、deno 或 bun 现在会遵循当前项目锁定的版本,而不再总是运行全局安装的版本。
如果项目指定了特定的运行时版本(通过 devEngines.runtime 或将运行时作为依赖项安装),那么在该项目内运行 node 时会使用该指定版本,而在项目外部运行时则使用全局版本。 你不再需要单独的版本管理器来实现这种行为。
控制此行为的设置是 globalShims,详细说明请参阅 项目感知型全局二进制文件。
Git 依赖解析
对于 GitHub、GitLab 和 Bitbucket 上的仓库,标识符现在代表的是身份,而不再是传输方式的选择。 所有这些都指向同一个依赖项,并且解析结果完全相同:
kevva/is-positive
github:kevva/is-positive
git+https://github.com/kevva/is-positive.git
git+ssh://git@github.com/kevva/is-positive.git
每一个都通过主机的规范 HTTPS URL 进行解析,且 pnpm 绝不会记录这些主机的 SSH URL。 特定机器连接主机时所使用的传输方式,取决于该机器自身的 Git 配置,而非项目本身的属性——因此,在配置了 SSH 密钥的笔记本电脑上生成的锁文件,即便在没有这些密钥的 CI 运行器上,依然可以正常进行安装。
在 pnpm 11 中,解析器会探测传输方式并可能记录下 git@github.com:owner/repo.git 这种格式,导致那些本地未配置该主机对应密钥的用户无法正常使用。 如果你的锁文件中包含由旧版本 pnpm 生成的此类条目,请使用 pnpm update <package> 重新解析一次这些依赖项——pnpm 不会自动重写该条目,因为锁文件记录的是具体要安装的内容。
若要通过 SSH 访问私有仓库,请在 Git 中配置重写规则,而不是在指定符中进行配置:
git config --global url."git@github.com:".insteadOf https://github.com/
pnpm 会调用 git,因此该重写规则会自动应用于其所有的 Git 操作。 相关细节(包括如何处理未知主机和包含凭证的 URL)请参阅 Git 依赖项的解析方式。
命名软件包管理器
自 v12.0.0-rc.6 版本起,pnpm 也会安装其他包管理器(包括 npm、Yarn Classic、Yarn Berry、Yarn 6 (yarnpkg/zpm) 和 Bun),因此提及其中某个名称时,指的是该工具本身,而非与其同名的 npm 包。
原因在于,npm 上的那些包并非该工具本身:npm 上的 yarn 仅停留在 Classic 版本,Yarn 4 是以 @yarnpkg/cli-dist 的形式发布的,Yarn 6 根本不在 npm 上,而 npm 上的 node 或 deno 包仅仅是用于下载对应构建版本的包装器。 以前,pnx yarn@4 install 会因版本缺失而失败,而 pnpm add -g yarn 安装的则是 Yarn 1。
| pnpm 11 | pnpm 12 | |
|---|---|---|
pnpm add yarn | 安装 npm 包 yarn | 在 packageManager / devEngines.packageManager 中记录项目的包管理器 |
pnpm add -g yarn | 安装 Yarn Classic | 安装当前的 Yarn 主线 |
pnpm add -g node / pnpm add -g deno | 安装一个包装器包 | 安装该 Node.js 或 Deno 版本 |
pnx node@22 / pnx deno | 安装一个包装器包 | 运行该版本 |
| 全局安装的软件包管理器 | 总是全局副本 | 遵循项目的引脚定义(如果存在的话)。 |
如果使用指向特定包(而非请求某个已发布版本)的标识符,安装的仍是该标识符所指定的包——例如 pnpm add yarn@npm:yarn@1.22.22 或 pnx yarn@yarnpkg/berry。
由此还可以引出另外两点。 对于托管在 Git 上的依赖项,系统会使用该依赖项所指定的包管理器来进行准备;因此,即便某台机器上仅安装了 pnpm,也能成功安装一个基于 Yarn 构建的代码仓库。 此外,pnpm shim add yarn 会链接一个 yarn 命令,该命令会运行当前项目所锁定的版本——pnpm setup 或安装操作绝不会自动创建这种垫片,因为它会覆盖 PATH 环境变量中原有的同名命令。
完整描述请见 其他包管理器。
循环依赖图的锁文件
自 v12.0.0-rc.5 版本起,pnpm 不再在遍历过程中随机遇到依赖循环时将其打破,而是改在固定的位置进行处理:循环中的包会按包 ID 排序,从而确保构成循环的边总是在同一位置被切断。
其结果是,锁文件仅取决于依赖图。 无论是调整 pnpm-workspace.yaml 中 packages 的 glob 模式顺序、调整 package.json 中的条目顺序,还是仅仅执行两次安装,最终生成的锁文件在字节层面上都是完全相同的——而在 pnpm 11 中,对于存在循环依赖的项目,这些操作可能会生成不同的锁文件。 对于存在大量循环依赖的工作区,解析对等依赖的速度快了 2 到 3 倍,内存占用减少了约 25%,且生成的锁文件显著变小;这是因为循环依赖中的包不再针对每一条到达它的路径生成独立的对等依赖变体。
现有的锁文件可继续使用:使用 --frozen-lockfile 选项进行的安装会直接使用它们而不作改动,而无需重新解析依赖关系的安装操作也不会改动这些文件。 第一个安装需要重新解决循环包的对等变量的重新键值,因此预计这类项目会出现一次性锁文件差异。 详细信息请参阅 对等解析是如何解析的。
pnpm install --resolution-only 已经消失
pnpm 12 未实现该标志并拒绝它:
error: unexpected argument '--resolution-only' found
该标志的作用是输出对等依赖相关的问题。 pnpm peers check 可直接完成此操作——它从锁文件中读取问题,因此既不需要重新解析依赖,也不需要执行安装:
pnpm peers check
如果你在 CI 脚本中调用了 --resolution-only,请注意这是此处唯一会导致构建终止(而非仅仅改变结果)的变更;因此,在进行切换之前,建议先搜索一下代码库中是否使用了该选项。
试试看
pnpm 12 已在 npm 上以 next-12 标签发布,并在 GitHub 上作为预发布版本发布。 Homebrew、winget、Scoop 和 Chocolatey 尚未提供它。 请参阅 安装 pnpm 12 RC 了解安装方法。
如果你遇到任何问题,请提交报告。
