如果你只是想找一个利用 Homebrew 安装 pnpm v7 的方案,执行 brew install ImSingee/pnpm/pnpm@7
即可
pnpm v8 在一个月前发布了,作为大版本更新之一,它引入了 lock file V6,同时停止支持了 V5。然而在给一些使用老版本的项目提 pr 的情况下,如果需要引入新的依赖就势必需要更新 lock file —— 这是不可被接受的,不能直接期望所有协作者都升级其 pnpm。
这引入了一个 pnpm V7 和 V8 共存的问题。这本不是难事,有着 Corepack 或者 pnvm 等工具。然而其对我而言都太重了 —— 一个 Homebrew 似乎就够了。
Homebrew 一个问题是,不支持安装旧版本 ,曾经引入过的 homebrew/versions 也早已被弃用,官方唯一建议的方案是自行托管 —— 当然,目前 pnpm 是没有维护官方旧版本的 tap 的,因此,只能自己动手喽。
创建 tap 根据官方指引 ,执行下面的命令即可创建一个空的 tap 库
1 brew tap-new ImSingee/homebrew-pnpm
注:这里 tap-new 后面的参数格式必须为 <repo>/homebrew-<name>
,这样可以通过 brew tap <repo>/<name>
来启用这个 tag,后续可以通过 brew install <repo>/<name>/<formula>
来直接安装相关包【另外实际上,如果 repo 名称不以 homebrew-
开头,这个命令会自动帮你加上这个前缀的】
然后会打印出类似下面的信息
1 2 3 4 5 6 7 8 9 10 11 12 Initialized empty Git repository in /opt/homebrew/Library/Taps/imsingee/homebrew-pnpm/.git/ [main (root-commit) 1b89b92] Create imsingee/pnpm tap 3 files changed, 90 insertions(+) create mode 100644 .github/workflows/publish.yml create mode 100644 .github/workflows/tests.yml create mode 100644 README.md ==> Created imsingee/pnpm /opt/homebrew/Library/Taps/imsingee/homebrew-pnpm When a pull request making changes to a formula (or formulae) becomes green (all checks passed), then you can publish the built bottles. To do so, label your PR as `pr-pull` and the workflow will be triggered.
大体意思就是,帮你在 /opt/homebrew/Library/Taps/imsingee/homebrew-pnpm
下创建了一个项目,并配置好了 GitHub Action 帮你测试、配置 bottle
我们新增一个 pnpm@7
的 Formula,这里是官方的 pnpm.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class Pnpm < Formula require "language/node" desc "📦🚀 Fast, disk space efficient package manager" homepage "https://pnpm.io/" url "https://registry.npmjs.org/pnpm/-/pnpm-8.3.1.tgz" sha256 "ce038ba2617f7a93d0b1f24b733b9d64258b15c97a14c6f37673c8d49e033d9a" license "MIT" livecheck do url "https://registry.npmjs.org/pnpm/latest" regex(/["']version["']:\s*?["']([^"']+)["']/i ) end bottle do sha256 cellar: :any_skip_relocation , arm64_ventura: "78ecd13f60c3baf6913933c8494ca17fc4e5b9f93c46bbc131312ffe41fe7f88" sha256 cellar: :any_skip_relocation , arm64_monterey: "78ecd13f60c3baf6913933c8494ca17fc4e5b9f93c46bbc131312ffe41fe7f88" sha256 cellar: :any_skip_relocation , arm64_big_sur: "78ecd13f60c3baf6913933c8494ca17fc4e5b9f93c46bbc131312ffe41fe7f88" sha256 cellar: :any_skip_relocation , ventura: "2f4f18876a3e2823f86f5500b7c47c173695e7f21eba007c2b7689dd12301145" sha256 cellar: :any_skip_relocation , monterey: "2f4f18876a3e2823f86f5500b7c47c173695e7f21eba007c2b7689dd12301145" sha256 cellar: :any_skip_relocation , big_sur: "4be656f6ff04e145810fb6e19f08fb01030798cec610c9d618b1fb01121d9f64" sha256 cellar: :any_skip_relocation , x86_64_linux: "78ecd13f60c3baf6913933c8494ca17fc4e5b9f93c46bbc131312ffe41fe7f88" end depends_on "node" => :test conflicts_with "corepack" , because: "both installs `pnpm` and `pnpx` binaries" def install libexec.install buildpath.glob("*" ) bin.install_symlink "#{libexec} /bin/pnpm.cjs" => "pnpm" bin.install_symlink "#{libexec} /bin/pnpx.cjs" => "pnpx" end def caveats <<~EOS pnpm requires a Node installation to function. You can install one with: brew install node EOS end test do system "#{bin} /pnpm" , "init" assert_predicate testpath/"package.json" , :exist? , "package.json must exist" end end
我们要进行几个小的修改
文件名官方为 pnpm.rb
,我们这里要改名为 [email protected]
以示区分
class 名称 Pnpm
我们需要修改成 PnpmAT7
url 这里我们要修改成我们所需的版本,目前 7 最新的版本是 7.32.2
sha256 我们这里需要修改成对应版本的 hash,目前 7.32.2 对应的是 f4b40caa0c6368da2f50b8ef891f225c24f14e7d60e42a703c84d3a9db8efede
livecheck
节下的 url 我们修改成 https://registry.npmjs.org/pnpm
、regex 为 /["']latest-7["']:\s*?"'["']/i
移除 bottle
最终修改好的版本是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class PnpmAT7 < Formula require "language/node" desc "📦🚀 Fast, disk space efficient package manager" homepage "https://pnpm.io/" url "https://registry.npmjs.org/pnpm/-/pnpm-7.32.2.tgz" sha256 "f4b40caa0c6368da2f50b8ef891f225c24f14e7d60e42a703c84d3a9db8efede" license "MIT" livecheck do url "https://registry.npmjs.org/pnpm" regex(/["']latest-7["']:\s*?["']([^"']+)["']/i ) end depends_on "node" => :test conflicts_with "corepack" , because: "both installs `pnpm` and `pnpx` binaries" def install libexec.install buildpath.glob("*" ) bin.install_symlink "#{libexec} /bin/pnpm.cjs" => "pnpm" bin.install_symlink "#{libexec} /bin/pnpx.cjs" => "pnpx" end def caveats <<~EOS pnpm requires a Node installation to function. You can install one with: brew install node EOS end test do system "#{bin} /pnpm" , "init" assert_predicate testpath/"package.json" , :exist? , "package.json must exist" end end
修改点的一些小解释 命名(文件名、也是 formula 名字)方面,首先必须要和官方的 pnpm 做出区分,而选择 pnpm@{VERSION}
这种格式则是和官方的其他多版本包格式保持一致(例如 postgresql、llvm 等均采用这种命名)。class 的名称和文件名要保持对应,pnpm@7
所对应的是 PnpmAT7
另外,我们的 [email protected]
文件可以选择存储在前面 tap-new 命令帮我们创建好的 Formula
目录下,也可以直接放在根目录下(还可以放在 HomebrewFormula 下)
url 和 sha256 是对应的包下载地址和对应包的下载文件哈希,我们可以利用 NPM Registry API 来获取最新的版本,并下载该版本对应的包来获取哈希
1 2 3 4 5 curl -s https://registry.npmjs.org/pnpm | jq '."dist-tags"."latest-7"' curl -s https://registry.npmjs.org/pnpm/-/pnpm-7.32.2.tgz | sha256sum
livecheck 是用来检测当前是否是最新版本的 ,pnpm 官方的 formula 是取的 latest,我们这里修改成取 latest-7
移除 bottle,因为这是自动化构建的内容,新的 formula 不应该包括
发布 在发布前,我们需要先执行下 brew style --fix [email protected]
来确认下 style 符合规范。
我们需要利用 Github Action 来触发测试和 bottle 的构建。在提交代码后不要直接 push 到主分支,而是提交一个 PR ,在通过所有测试后 给其添加 pr-pull
标签。
然后任何人就都可以直接安装我们的 pnpm@7
啦!
1 2 3 4 5 6 brew tap ImSingee/pnpm brew install pnpm@7 brew install ImSingee/pnpm/pnpm@7
发布后的仓库在 https://github.com/ImSingee/homebrew-pnpm ,欢迎使用和 star :-)
安装后的一个小 tips 命名使用 <name>@{VERSION}
的一个好处在于,其不会污染我们目前在使用的环境,这可以在安装后有一个提示看出
1 2 3 4 5 pnpm@7 is keg-only, which means it was not symlinked into /opt/homebrew, because this is an alternate version of another formula. If you need to have pnpm@7 first in your PATH, run: echo 'export PATH="/opt/homebrew/opt/pnpm@7/bin:$PATH"' >> ~/.zshrc
与一般的 formula buts,这种会被检测到是另一个程序的不同版本,因此不会安装到系统的 PATH 下,而是独立的放在额外的路径。
根据提示,如果我们想要执行 7 版本的 pnpm,则需要使用全路径 /opt/homebrew/opt/pnpm@7/bin/pnpm
,如果想要让这个作为主版本的话,可以将 /opt/homebrew/opt/pnpm@7/bin
加入至 PATH 中。
当然,我的做法是做一个 symlink
1 2 ln -s /opt/homebrew/opt/pnpm@7/bin/pnpm /usr/local/bin/pnpm7ln -s /opt/homebrew/opt/pnpm@7/bin/pnpx /usr/local/bin/pnpx7
参考 https://docs.brew.sh/How-to-Create-and-Maintain-a-Tap
https://stackoverflow.com/questions/3987683/homebrew-install-specific-version-of-formula