JavaScript 套件管理器比較:npm / yarn / pnpm

比較 npm、yarn、pnpm 的差異:node_modules 結構、幽靈依賴、磁碟與速度、lockfile、monorepo 與選型

npm 本身的深入用法(package.json、指令、版本、腳本)見 npm 完全指南;套件管理器在生態中的定位見 JavaScript 生態全景


目錄


什麼是套件管理器?

套件管理器(Package Manager) 負責:從 npm registry 下載你專案依賴的套件、裝進 node_modules、用 lockfile 鎖定版本、並提供執行 package.json scripts 的入口。

package.json(宣告要哪些套件)
   │ 套件管理器
node_modules(實際裝進來的套件)+ lockfile(鎖定確切版本)

npm、yarn、pnpm 做的是同一件事,差別在怎麼存、怎麼連、多快、多省空間、多嚴格


三者簡介

管理器 來歷 一句話特色
npm Node.js 內建(預設) 最普及、零安裝即有
yarn Facebook 2016 推出 當年比舊 npm 快、帶 lockfile/workspaces;v2+(Berry)改用 PnP
pnpm performant npm 全域 store + 連結 → 最省磁碟、最快、最嚴格

補充:Bun 也內建套件管理(bun install),相容 npm 生態、主打速度。本篇聚焦三大主流。


共同點

換管理器多數情況不必改程式,因為它們:

  • 用同一個 npm registry:套件來源相同
  • 都讀 package.json:依賴宣告格式一致
  • 指令概念相近:install / add / remove / run
  • 都產生 lockfile:只是檔名與格式不同

所以「換 pnpm」通常只是換指令與重裝,不是換生態。


關鍵差異

面向 npm yarn (classic) pnpm
node_modules 結構 扁平、提升(hoisting) 扁平、提升 符號連結 + 全域 store
幽靈依賴 易發生 易發生 嚴格避免
磁碟用量 高(每專案複製) 低(硬連結共用)
安裝速度 最快
lockfile package-lock.json yarn.lock pnpm-lock.yaml
monorepo workspaces workspaces workspaces(體驗佳)
內建於 Node

下面挑最關鍵的幾點展開。


node_modules 結構與幽靈依賴

這是 pnpm 與 npm/yarn 最本質的差異。

npm / yarn:扁平提升(hoisting)

把所有依賴(含依賴的依賴)盡量「提升」到 node_modules 頂層攤平:

node_modules/
  your-lib/
  lodash/        ← 其實是 your-lib 的依賴,卻被提到頂層

問題:幽靈依賴(phantom dependencies)——你的程式可以 import lodash,即使你沒在 package.json 宣告它(它只是別人的依賴剛好被提上來)。哪天那個間接依賴改版移除 lodash,你的程式就突然壞掉。

pnpm:符號連結 + 全域 store

pnpm 的 node_modules 只放你真正宣告的套件(用 symlink 指向全域 store),間接依賴藏在 .pnpm/ 下:

node_modules/
  your-lib  → 連結到全域 store
  .pnpm/    ← 間接依賴放這,不攤平到頂層

結果:你只能 import 你宣告過的套件,沒宣告的 import 不到 → 杜絕幽靈依賴,依賴關係更誠實。


磁碟與速度

pnpm 用「全域內容定址 store + 硬連結」:同一版套件在整台機器只存一份,各專案用硬連結指過去,不重複複製。

npm/yarn:每個專案各自複製一份 node_modules → 10 個專案 = 10 份
pnpm:    全域存一份,專案用硬連結 → 10 個專案幾乎不額外佔空間
  • 磁碟:pnpm 大幅省(多專案時差距明顯)
  • 速度:pnpm 安裝通常最快(已在 store 的套件直接連結,不必重抓重解壓)

Lockfile

三者都用 lockfile 鎖定確切版本與依賴樹,確保「在你機器和 CI 上裝到的完全一樣」:

管理器 lockfile
npm package-lock.json
yarn yarn.lock
pnpm pnpm-lock.yaml

原則:lockfile 一定要進版控,且團隊統一一種管理器——混用會產生多個 lockfile、裝出不一致的依賴樹。


Monorepo / Workspaces

三者都支援 workspaces(一個 repo 管多個 package,彼此可本地互相引用):

// package.json(根)
{ "workspaces": ["packages/*"] }
  • pnpm 在 monorepo 的依賴隔離與速度上體驗最佳,是大型 monorepo 的熱門選擇
  • 也常搭配 Turborepo / Nx 等 monorepo 工具

指令對照

動作 npm yarn pnpm
安裝全部依賴 npm install yarn pnpm install
加套件 npm install pkg yarn add pkg pnpm add pkg
加開發依賴 npm install -D pkg yarn add -D pkg pnpm add -D pkg
移除 npm uninstall pkg yarn remove pkg pnpm remove pkg
執行 script npm run dev yarn dev pnpm dev
執行一次性套件 npx pkg yarn dlx pkg pnpm dlx pkg
CI 嚴格安裝 npm ci yarn install --frozen-lockfile pnpm install --frozen-lockfile

怎麼選

要零安裝、最普及、團隊不想折騰
  → npm(Node 內建,預設選擇)

多專案 / monorepo、在意磁碟與速度、想杜絕幽靈依賴
  → pnpm(現代專案越來越主流)

既有專案already用 yarn、或需要 Yarn Berry 的 PnP / 特定功能
  → yarn

實務建議:

  • 新專案:npm(簡單)或 pnpm(效能 + 嚴格),二選一
  • monorepo / 多專案開發:pnpm 體驗最佳
  • 最重要的是團隊統一一種,並把 lockfile 進版控

常見問題

問題 1:換套件管理器要改程式嗎?

通常不用。它們用同一個 registry、讀同一份 package.json,換的只是指令與 node_modules 的組織方式。換時刪掉舊 node_modules 與舊 lockfile,用新管理器重裝即可。

問題 2:什麼是幽靈依賴(phantom dependency)?

你能 import 一個沒在 package.json 宣告的套件——因為它是別人的間接依賴被「提升」到 node_modules 頂層。風險是該間接依賴一改版移除它,你的程式就壞。pnpm 用嚴格的 node_modules 結構杜絕這問題。

問題 3:pnpm 為什麼比較省空間又快?

它把每版套件在整台機器只存一份(全域 content-addressable store),各專案用硬連結指過去,不重複複製、不重複下載解壓。多專案時省磁碟、安裝也快。

問題 4:可以同時用 npm 和 pnpm 嗎?

同一個專案不建議——會產生多個 lockfile、依賴樹不一致。團隊應統一一種,並只提交那一種 lockfile。

問題 5:lockfile 要進版控嗎?

要。lockfile 鎖定確切版本與依賴樹,確保所有人與 CI 裝到完全一致的依賴。不提交會導致「我的機器正常、別人/CI 壞掉」。


總結

核心要點

  • npm / yarn / pnpm 都是 JS 套件管理器,用同一 registry、讀同一 package.json,做同一件事
  • 差別在怎麼存與連:npm/yarn 扁平提升(易有幽靈依賴);pnpm 用全域 store + 連結(省磁碟、快、杜絕幽靈依賴)
  • 三者都有 lockfile(檔名不同)與 workspaces(monorepo)
  • 選型:npm(內建普及)/ pnpm(效能 + 嚴格 + monorepo)/ yarn(既有專案 / Berry PnP)
  • 鐵則:團隊統一一種 + lockfile 進版控

快速參考

npm yarn pnpm
內建 Node
磁碟
速度 最快
幽靈依賴 杜絕
lockfile package-lock.json yarn.lock pnpm-lock.yaml

建立日期:2026-06-18

🔗相關文章