pnpm init --init-package-manager 怎麼固定版本?11.25.0 會改看 latest
執行 pnpm init --init-package-manager 後,如果新建立的專案 pin 不是你目前正在執行的 pnpm 版本,不一定是指令失敗。pnpm 11.25.0 的行為已改成查 registry 的 latest tag,讓新專案可以直接固定到較新的可用版本;但這也會讓本機、CI 和文章裡的預期看起來不一致。
先講結論:從 pnpm 11.25.0 與 12.0.0 開始,--init-package-manager 會嘗試把 pin 設成 registry 的 latest;如果查詢失敗、太慢、被 offline/minimumReleaseAge/trustPolicy 阻擋,就回退到目前執行中的 pnpm,而且不會因為 latest 比目前版本舊就降版。 這個行為和「如何更新 pnpm 本身」是兩件事。
先確認你看到的是執行版本還是專案 pin
不要只貼一個 pnpm --version 就判斷專案版本。先把三種資訊分開留下:
pnpm --versionnode --versionpnpm config get registry接著檢查專案 manifest 與 lockfile 裡是否已有 package manager 宣告:
node -e 'const p=require("./package.json"); console.log(JSON.stringify({packageManager:p.packageManager, devEngines:p.devEngines}, null, 2))'rg -n 'packageManager|packageManagerDependencies' package.json pnpm-lock.yaml這裡有三個可能不同的值:正在執行的 pnpm、package.json 裡的 devEngines.packageManager 或 legacy packageManager,以及 lockfile 裡解析後的 packageManagerDependencies。它們不一致時,先記錄來源,不要直接刪除其中一個。
--init-package-manager 在 11.25.0 之後怎麼決定版本
官方 pnpm 文件對這個旗標的規則,可以整理成以下順序:
| 條件 | pnpm init --init-package-manager 的結果 |
|---|---|
可以查到 registry 的 latest | 以 latest 作為候選 pin;它可以比目前執行版本新 |
| latest 比目前執行版本舊 | 不把既有選擇降到較舊版本 |
| registry 查詢失敗、逾時或使用 offline | 回退到目前正在執行的 pnpm |
| minimumReleaseAge 或 trustPolicy 讓候選版本不可用 | 回退到目前正在執行的 pnpm |
使用 --no-init-package-manager | 不新增 package manager pin |
這個設計兼顧了兩個目標:新專案可以跟上 registry 的最新 stable 版本,而離線或受限環境不會因為「無法查 latest」就讓 pnpm init 失敗或無限等待。也因此,同一條指令在有網路的開發機與隔離 CI runner 可能留下不同 pin,必須把結果納入 code review。
實際跑一次,差異要看兩個檔案
在空白資料夾或 disposable branch 測試,不要直接在正式 workspace 裡覆蓋既有 manifest:
mkdir pnpm-init-pin-checkcd pnpm-init-pin-checkpnpm init --init-package-managergit diff -- package.json pnpm-lock.yaml如果資料夾還沒有 git repository,git diff 不一定會顯示未追蹤的 package.json;可以直接檢查內容與 lockfile:
node -e 'const p=require("./package.json"); console.log(JSON.stringify({packageManager:p.packageManager, devEngines:p.devEngines}, null, 2))'rg -n 'packageManager|packageManagerDependencies' package.json pnpm-lock.yaml從 pnpm v11 開始,專案 pin 主要會寫到 devEngines.packageManager;較新的文件也說明,解析後的實際版本會記在 pnpm-lock.yaml 的 packageManagerDependencies。部分專案仍會看到 legacy packageManager 的 exact version,因此升級或重建時要以目前專案格式和 lockfile 一起審查。
為什麼本機和 CI 會得到不同結果
最常見不是 pnpm 隨機選版本,而是兩邊的輸入不同:
- 本機能連 registry,CI 使用
--offline或沒有 DNS。 - 本機沒有 minimum release age,CI 的設定拒絕剛發布的 latest。
- 本機的 pnpm 已較新,CI 仍使用舊版執行器。
- 兩邊的 registry、trust policy 或認證設定不同。
- 指令在 workspace 子套件執行,但真正的 pin 只應寫在 workspace root。
官方文件特別提醒,在 workspace 內的子套件執行 pnpm init --init-package-manager 時,這個旗標只對 root 有效。若你希望整個 monorepo 使用同一個 pnpm,應在 root 產生或審查 pin,再讓 CI 顯式執行該版本,不要期待每個 subpackage 都有自己的 package manager 設定。
不想自動寫 pin,就用 no-init
如果專案版本由 Corepack、mise、Volta、asdf 或 CI image 統一管理,初始化時可以明確關閉 pin:
pnpm init --no-init-package-manager這不代表專案沒有版本管理,而是把責任留給既有工具。相反地,如果團隊希望新專案自帶可審查的 pnpm 版本,就保留 --init-package-manager,然後把 package.json 與 pnpm-lock.yaml 一起提交,並在 CI 印出:
pnpm --versionpnpm install --frozen-lockfile這樣 code review 看到 pin 變更時,可以分辨它是初始化時查到新的 latest,還是依賴更新造成的 lockfile 變更。
不要把 init 的 pin 和 pnpm 自身更新混在一起
--init-package-manager 是「在專案寫入或更新 package manager pin」;它不等同於把目前使用中的 pnpm 全域升級。pnpm 11.25.0 的 release note 也提醒,pnpm update -g 不再負責改變 pnpm 本身的版本;需要更新 pnpm 執行器時,應依官方建議使用 pnpm self-update 或團隊既有的版本管理流程。
排查時可以依序問:
- 是哪個 pnpm 執行了
init? - registry 的 latest 當時解析成什麼?
package.json寫的是devEngines.packageManager還是 legacypackageManager?- lockfile 是否留下
packageManagerDependencies? - CI 是否有 offline、minimumReleaseAge 或 trust policy?
回答完這五題,通常就能判斷版本差異是預期的解析結果,還是真正的環境漂移。
結論:把 latest 查詢結果當成輸入的一部分
pnpm 11.25.0 之後,pnpm init --init-package-manager 不再只看「目前正在執行的版本」,而會嘗試查 registry 的 latest;pnpm 12.0.0 也沿用這個方向。可用網路時 pin 可能前進到較新版本,查詢受限時則回退到 running version,而且不會把選擇降到較舊版本。
因此,遇到「init 後版本不一樣」時,先檢查 devEngines.packageManager、legacy packageManager、lockfile、registry 與 workspace root。需要穩定重現時,把實際 pin、Node、pnpm 和 CI 網路政策一起提交與驗證;不需要 pin 時,初始化就明確使用 --no-init-package-manager。
常見問題
Q: pnpm init --init-package-manager 為什麼會寫入比目前 pnpm 更新的版本?
A: pnpm 11.25.0 起會查 registry 的 latest,官方允許候選 pin 比目前執行版本新。這是初始化時的版本解析,不代表本機的 pnpm --version 已經同步變更。
Q: offline 時執行 init 會失敗嗎?
A: 官方文件描述的 fallback 是使用目前正在執行的 pnpm;registry 無法連線、查詢太慢、--offline 或政策拒絕候選版本時,不應為了查 latest 而卡住。仍要把產生的 manifest 與 lockfile 納入審查。
Q: workspace 子套件可以各自固定不同 pnpm 嗎?
A: --init-package-manager 在 workspace 子套件執行時只對 root 有效。若真的需要不同版本,應先確認工具與 CI 是否支援該拓樸;一般 monorepo 建議在 root 保留單一可審查 pin。
參考資料:
回報錯字、失效連結,或告訴我你想看的延伸主題。