npm → pnpm
你熟的 npm 指令與對應的 pnpm 寫法並排,並說明 node_modules 不再攤平之後,實際上會有什麼東西壞掉。
在你的瀏覽器中執行
| 要做的事 | npm | pnpm |
|---|---|---|
| 安裝 lockfile 裡的全部相依 | ||
| CI 安裝,lockfile 若會改動就失敗 | ||
| 新增相依套件 | ||
| 新增開發相依 | ||
| 鎖定版本,不用範圍 | ||
| 全域安裝 | ||
| 移除相依套件 | ||
| 在既有版本範圍內更新 | ||
| 列出落後最新版的套件 | ||
| 執行 package.json 裡的 script | ||
| 不安裝就執行套件的執行檔 | ||
| 建立新套件 | ||
| 查出某個套件為什麼被裝進來 | ||
| 檢查相依套件的安全通報 | ||
| 把相依裝到某一個 workspace |
簡短版
| npm | pnpm |
|---|---|
npm install | pnpm install,或 pnpm i |
npm install <pkg> | pnpm add <pkg> |
npm install -D <pkg> | pnpm add -D <pkg> |
npm uninstall <pkg> | pnpm remove <pkg> |
npm run build | pnpm build |
npx <pkg> | pnpm dlx <pkg> |
npm install <pkg> -w <name> | pnpm --filter <name> add <pkg> |
pnpm 的指令刻意做得跟 npm 很接近,所以這一層翻譯幾乎是機械式的。完整的表格在上面,可以填入你 自己的套件名稱。
真正改變的是什麼
指令是簡單的部分。安裝出來的結構才是你換過去的理由,也是東西壞掉的理由。
node_modules 不是攤平的。 npm 與 Yarn 1 會把所有間接相依提升到最上層,於是程式碼可以
require('某個套件')——即使 package.json 裡從來沒宣告過它——而且真的會動。pnpm 只把你宣告過的
相依放在最上層,其餘全部從一個 content-addressed 的 store 用 symlink 連進去。
這確實抓得出 bug,而且抓出來的多半在別人寫的套件裡。依賴提升的套件在 pnpm 下會直接
Cannot find module。解法通常是在 .npmrc 加 public-hoist-pattern,有時候是去上游開 issue。
硬碟用量會直接垮下來。 每個套件的每個版本在一台機器上只存一份,再 hard link 進各個專案。 十個專案用同一版 React,只佔一份。
pnpm dlx 不是換名字的 npx。 npx 會優先執行本地 node_modules 裡已有的執行檔;
pnpm dlx 一律抓到暫存區再執行。要跑本地的執行檔請用 pnpm exec。
遷移一個專案
- 刪掉
package-lock.json與node_modules。 - 執行
pnpm install。 - 跑一次 build 和測試。提升假設是在這裡爆的,不是在安裝的時候。
- Commit
pnpm-lock.yaml,而且只 commit 這一個。
monorepo 還要加一個 pnpm-workspace.yaml。pnpm 不讀 package.json 裡的 workspaces
欄位——這是最多人卡住的一點,因為安裝會成功,只是什麼都沒連起來。
相關
npm 轉 Yarn,或含 Bun 的 四欄完整對照表。