Rian

嘿,日安

【前端開發必備工具系列】之三:pnpm - 更快、更節省空間的套件管理方案

Posted at # Front-end

簡介

pnpm(performant npm),主要目標在於提升速度與效能,並且減少磁碟空間。使用獨特的安裝策略:當你使用 pnpm 安裝套件時,他會將每個套件的版本儲存全域的儲存目錄( pnpm-store,以下簡稱 Store)中,接著 node_modules 會建立一個指向 Store 對應版本套件的硬連結。每個套件的各版本都有唯一的子目錄,不復刻各個專案的 node _modules,這大大的節省了本地的儲存空間並加速下載速度。安裝位置通常在 ~/Library/pnpm/store (mac 系統)。

工作區(workspace)

支援 Monorepo 架構,使用 pnpm-workspace.yaml 可以定義工作區,工作區如果有相依性,彼此使用軟連結又稱符號連結(symlink)。

硬連結允許不同位置可以訪問同一個檔案。也就是說專案下的 node_modules 檔案目錄只包含指向 Store 中的連結。硬連結是讓多個檔案名稱關聯到目標指向檔案,所以硬連結是檔案不是目錄。

以安裝 express 為例,左是 npm 安裝的方式,右是 pnpm。過往 npm 會將 express 所依賴的套件扁平化安裝在 node_modules 之中;pnpm 所要解決的問題從下圖我們可以看到 pnpm 透過符號連結的方式引用。

npm-pnpm-archivist.png

符號連結是一個特殊檔案,裡面包含了其他檔案或是目錄的路徑。pnpm 會使用符號連結來管理套件之間的連結關係。

symlink-refer.png

總整理

硬連結

  • 主要用途:將套件從本地端 Store 連結到各個專案。
  • 進到 Store 的 files 目錄下可以查看到各個不同的資料夾,裡面全部都是硬連結檔案。由於日安底子不夠深,裡面內容無法探究及驗證。

符號連結、軟連結

  • 主要用途:處理套件之間的相依性。
  • 屬於連結檔案類型,使用 l 命令查看。
  • 在專案中安裝套件後會自動在 node_modules/.pnpm 目錄中建立軟連結,移除套件後,查看專案下 node_modules/.pnpm ,軟連結仍然存在。

透過官網文件我們可以知道關係如下:

illustration-of-the-principle-of-pnpm.png

常用命令:

  • pnpm install
  • pnpm add [package]
  • pnpm run [script]
  • pnpm remove [package]

延伸思考

yarn 既然已經很棒了 我們為什麼又需要 pnpm?

  • yarn 及 npm 與 pnpm 相比,省更多磁碟空間,下載的速度也有所不同。
  • pnpm 提供更嚴格的套件解析算法,確認每個套件都只被安裝過一次,避免重複安裝跟版本衝突。
  • pnpm 天然支援 Monorepo 架構。

在 yarn 或 pnpm 的專案下 我還需要 package.json 以及 package.lock.json 嗎?

  • 我們需要 package.json,因為他是 Node.js 專案的核心檔案,不管你使用哪種套件管理工具都需要。
  • 之前我們說到 lock 檔案是管理套件中所相依的套件版本,所以這有所不同。yarn 使用 yarn.lock 作為其鎖定檔案,而 pnpm 使用 pnpm-lock.yaml
  • 我們使用了yarn.lock或是pnpm-lock.yaml,之後都不需要,也不應該有package-lock.json檔案,如果檔案並存有可能會混淆或是引發潛在的衝突。
  • 如果你的專案曾經使用過 npm 並且有package-lock.json,未來想要切換成 yarn 或是 pnpm,需要將package-lock.json移除。

如果我使用 yarn 或是 pnpm 我還可以使用 npx、nvm 等指令嗎?

  • npx 會先在專案的 node_modules/.bin 目錄中尋找可以執行的檔案,如果找不到,則會在全域的套件安裝路徑中尋找,因此不受影響。
  • nvm 是用於管理多個 Node.js 版本的工具,無論是 yarn 還是 pnpm 都會需要依賴 Node.js 環境,但須要注意的是在切換 Node.js 版本時,yarn 或是 pnpm 有可能會需要重新安裝,因為他們必須對應到符合的 Node.js 環境。

有可能在 npm 可以安裝套件,但是在 yarn 或是 pnpm 無法安裝的情況嗎?

  • 通常是不會發生,因為他們三者都共用 npm Registry。

  • 如果套件使用 npm 特有的命令或語法有可能 yarn 或 pnpm 沒辦法安裝。

  • 如果套件的相依性複雜,也可能沒辦法安裝。比方說:專案使用兩個套件,他們使用相同子套件,卻不同版本,npm 會安裝比較新版本的套件 B,但 yarn 或 pnpm 有可能會報錯。

    Terminal window
    my-project/
    ├── package.json
    └── ...
    package-a/
    ├── package.json (依賴 package-c@^1.0.0)
    └── ...
    package-b/
    ├── package.json (依賴 package-c@^2.0.0)
    └── ...