如果你只是想找一个利用 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 库
brew tap-new ImSingee/homebrew-pnpm
注:这里 tap-new 后面的参数格式必须为 <repo>/homebrew-<name>
,这样可以通过 brew tap <repo>/<name>
来启用这个 tag,后续可以通过 brew install <repo>/<name>/<formula>
来直接安装相关包【另外实际上,如果 repo 名称不以 homebrew-
开头,这个命令会自动帮你加上这个前缀的】
然后会打印出类似下面的信息
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
增加一个 formula#
我们新增一个 pnpm@7
的 Formula,这里是官方的 pnpm.rb
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
,我们这里要改名为pnpm@7.rb
以示区分 - 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
最终修改好的版本是
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
另外,我们的 pnpm@7.rb
文件可以选择存储在前面 tap-new 命令帮我们创建好的 Formula
目录下,也可以直接放在根目录下(还可以放在 HomebrewFormula 下)
url 和 sha256 是对应的包下载地址和对应包的下载文件哈希,我们可以利用 NPM Registry API 来获取最新的版本,并下载该版本对应的包来获取哈希
# 获取当前的 V7 最新版本
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 pnpm@7.rb
来确认下 style 符合规范。
我们需要利用 Github Action 来触发测试和 bottle 的构建。在提交代码后不要直接 push 到主分支,而是提交一个 PR ,在通过所有测试后给其添加 pr-pull
标签。
然后任何人就都可以直接安装我们的 pnpm@7
啦!
# case 1: enable tap
brew tap ImSingee/pnpm
brew install pnpm@7
# case 2: simple install single
brew install ImSingee/pnpm/pnpm@7
发布后的仓库在 https://github.com/ImSingee/homebrew-pnpm,欢迎使用和 star :-)
安装后的一个小 tips#
命名使用 <name>@{VERSION}
的一个好处在于,其不会污染我们目前在使用的环境,这可以在安装后有一个提示看出
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
ln -s /opt/homebrew/opt/pnpm@7/bin/pnpm /usr/local/bin/pnpm7
ln -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