pnpm 12 穩定嗎?從 RC lockfile 驗證到正式版升級
pnpm 12 已經不是 RC:官方在 2026 年 8 月 26 日發布 v12.0.0。這篇文章原本用 RC 版本整理 lockfile 驗證,現在改以正式版為基準,保留 RC 測試時最值得注意的 dependency cycle、workspace 和 pinned package manager 檢查。
直接結論是:可以把 pnpm 12.0.0 放進隔離的 CI matrix 和 canary,但不要只在本機更新 global pnpm 就宣布全團隊升級。 先固定 Node、registry、pnpm 版本,驗證既有 lockfile 的 frozen install,再在 disposable branch 觀察真正重新解析時的差異;正式環境要保留明確的回退 pin。
先分清正式版、RC 與安裝來源
pnpm 12.0.0 是正式 release,12.0.0-rc.11 則是升級前的候選版本。至於不帶版本的安裝指令會拿到哪一個 major,仍取決於 registry 的 dist-tag、套件管理器或團隊的版本工具;不要用 npm install --global pnpm 的結果代替專案 pin。
| 版本或來源 | 適合的用途 | 你要留下的證據 |
|---|---|---|
[email protected] | 正式版升級、canary 與 production CI | release tag、Node 版本、lockfile diff |
[email protected] | 已結束的 RC 回歸或重現案例 | RC release note 與測試結果 |
未指定版本或 latest | 互動式試用,不適合當部署輸入 | 執行時解析出的實際版本 |
先查清楚目前執行的是哪一個 pnpm:
pnpm --versionnode --versionnpm view pnpm dist-tags --json要測正式版時,請在隔離環境明確安裝和驗證:
pnpm --version團隊若已經使用 Corepack、mise 或其他版本管理器,沿用既有流程即可;重點是把 12.0.0 寫進可審查的 pin,並讓每個 CI job 印出實際版本。
pnpm 12 會影響 lockfile 的四個邊界
正式版 release note 的重點不只是一個版本號。升級前先把變更拆成可驗證的邊界:
| pnpm 12 變更 | 實際要檢查什麼 |
|---|---|
| GitHub、GitLab、Bitbucket 等已知 host 的 Git 依賴統一使用 canonical HTTPS identity | lockfile 不再因某台機器能否使用 SSH 而記錄不同 transport;private repository 要在執行機器設定 Git rewrite |
pnpm-workspace.yaml 不再默默忽略未知設定 | 拼錯設定時,符合專案 pnpm pin 的執行會回報 ERR_PNPM_UNRECOGNIZED_WORKSPACE_SETTINGS |
| peer resolution 會以 canonical 順序拆解 dependency cycle | 相同 dependency graph、不同 importer 或 dependency 順序,應產生 byte-identical lockfile |
Linux 的 packageImportMethod: auto 會先嘗試 hardlink | btrfs 的 warm store 安裝路徑要測時間與 inode 行為;macOS 仍以 clone-first 為主 |
上述變更不代表所有既有 lockfile 都要重寫。只執行 headless 或 frozen install 時,既有 lockfile 應能被消費;真正觸發 dependency resolution 的時機,才是需要審查 re-key 或 graph 差異的時機。
第一條路徑:只驗證既有 lockfile
先在乾淨工作副本或 CI runner 測試正式版能否消費目前提交,不要一開始就用 --lockfile-only 產生大量 diff:
git status --shortpnpm --versionpnpm install --frozen-lockfilegit diff --exit-code -- pnpm-lock.yaml如果 frozen install 失敗,先閱讀 pnpm frozen lockfile 錯誤怎麼修,分辨是 manifest 漂移、pnpm pin 不一致、registry 差異,還是正式版的新行為。不要為了讓 pipeline 繼續就刪除 lockfile。
這條路徑的完成條件是:pnpm 版本、Node 版本、registry 與 lockfile 都能被記錄,安裝不改寫 pnpm-lock.yaml,接著 lint、test 和 build 都通過。它不能證明重新解析一定沒有差異,但能先確認升級不會破壞既有提交。
第二條路徑:在 disposable branch 觀察重新解析
只有在第一條路徑通過後,才在 disposable branch 或暫存工作副本重新解析:
cp pnpm-lock.yaml /tmp/pnpm-12-before-resolve.yamlpnpm install --lockfile-onlygit diff -- package.json pnpm-workspace.yaml pnpm-lock.yaml把 diff 分成三類審查:
- manifest 或 catalog 刻意改動造成的版本更新。
- dependency cycle、peer variant 或 importer 順序造成的 canonical re-key。
- 不應出現的 registry、integrity、無關套件版本或 dependency graph 變更。
pnpm 12 的 release note 明確說明,第一次真的重新解析時,cycle-heavy package 的既有 peer variant 可能只重建一次;這不等於每次 pnpm install 都會漂移。若無關套件也被改寫,先保存最小重現案例,再決定是否暫停升級。
Git 依賴:讓 SSH 私有倉庫留在機器設定
pnpm 12 對 GitHub、GitLab、Bitbucket 的已知 host 會把不同寫法視為同一個 repository identity,lockfile 不再記錄該 host 的 SSH URL。公開 archive 可用時會走 host 的 archive;需要權限的 repository 則透過 canonical HTTPS URL 執行 Git 操作。
如果私有倉庫在 CI 必須透過 SSH 取用,依官方 release note 把 rewrite 設在執行機器,而不是把某台機器的 SSH URL 硬寫進專案 lockfile:
這個設定應由 CI image 或 runner provisioning 管理,並用最小權限的 deploy key 或既有認證方式驗證。不要把 token、私鑰或帶有帳密的 URL 寫入 package.json、lockfile 或文章範例。
workspace 設定拼錯,pnpm 12 會更早告訴你
過去 pnpm-workspace.yaml 中不認得的設定可能被靜默忽略;pnpm 12 會回報未知設定,若專案 pin 的 pnpm 版本符合目前執行版本,命令會失敗並給出 ERR_PNPM_UNRECOGNIZED_WORKSPACE_SETTINGS。這是好事,但會讓原本「看似成功」的 CI 變成明確失敗。
升級前先在 workspace 內找出拼字或版本差異,並保留檢查設定的能力:
pnpm config listpnpm install --frozen-lockfilepnpm config 子命令不會因為未知 workspace setting 而無法讀取設定,因此可以先用它確認問題,再修正 pnpm-workspace.yaml。修正設定後要把 manifest、workspace 檔案和 lockfile 分開審查,避免把 typo 修復誤判成 resolver 變更。
CI matrix 不要只測一台 macOS
正式版升級至少要有一個乾淨 runner,並依專案實際部署環境覆蓋 Node、作業系統、檔案系統和 cache 狀態:
- cold install 與 warm store install 各一次。
- frozen install、lint、test、build 都通過。
- monorepo 的 importer 順序、peer dependency、
workspace:和 catalog 案例都存在。 - Linux btrfs 若使用
packageImportMethod: auto,要觀察 hardlink 路徑;不要把 btrfs 結果套到 ext4 或 macOS。 - 若含 private Git dependency,CI runner 必須用與 production 相同的認證與 Git rewrite。
同一份 package.json、pnpm-workspace.yaml 和 lockfile 在兩個乾淨工作副本中重新解析,若結果不同,先比較 Node、pnpm、registry、環境變數和檔案系統,不要先修改 lockfile 來掩蓋差異。
升級與回退的最小流程
可以把升級拆成這 6 個可審查步驟:
- 以
[email protected]建立獨立 CI job,保留現有 stable major 的 job。 - 在 clean runner 執行 frozen install,確認 lockfile 沒有被改寫。
- 在 disposable branch 執行 lockfile-only resolution,分類所有 diff。
- 修正 workspace unknown settings,補上 private Git dependency 的 runner 設定。
- 執行 lint、test、build 與實際 packaging/deploy smoke test。
- 通過 canary 後才把專案 pin 與 production image 一起更新,並保留上一個可重現版本。
若需要明確 pin,可以在專案的 package.json 保留 package manager 宣告:
{}回退時不要只把 global pnpm 降版;要同時還原 package manager pin、CI image、Node、registry 設定和 lockfile。這樣才能知道失敗是 resolver、執行環境還是應用程式測試造成的。
結論:正式版可測,但證據要跟著 pin 走
pnpm 12.0.0 已正式發布,適合開始做團隊升級和 CI canary。它對 known-host Git dependency、workspace typo、dependency cycle 與 Linux package import 都有可觀察的行為變更;最安全的判斷方式不是看版本號,而是以固定輸入重跑 frozen install、重新解析、測試與 build,並留下能回退的 pin 和 lockfile 證據。
常見問題
Q: pnpm 12 已正式發布,可以直接執行 npm install --global pnpm 嗎?
A: 不建議把未指定版本當成部署輸入。registry 的 latest、版本管理器和專案 pin 可能不同;請用 [email protected] 明確安裝或沿用團隊版本工具,並在 CI 印出 pnpm --version。
Q: pnpm 12 會讓所有既有 lockfile 重新產生嗎?
A: 不會。既有 lockfile 可以由 frozen install 消費;只有 dependency graph、manifest 或設定真的觸發重新解析時,才可能看到 cycle 或 peer variant 的 canonical re-key。任何無法解釋的 registry、integrity 或無關套件差異都應先保存案例。
Q: frozen install 在升級後失敗,應該刪除 lockfile 嗎?
A: 不要先刪除。先確認 package manager pin、Node、registry、manifest 和 workspace 設定,再依錯誤內容判斷是否需要在隔離分支重新解析。刪除 lockfile 會讓真正的相容性問題更難追蹤,也會擴大版本變更範圍。
參考資料:
回報錯字、失效連結,或告訴我你想看的延伸主題。