如果你只是想找一個利用 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