跳到主要內容

扁平的 node_modules 並非唯一的方式

· 3 分鐘閱讀時間

pnpm 的新使用者經常問我關於 pnpm 建立的 node_modules 的奇怪結構。為什麼它不是扁平的?所有子依賴項在哪裡?

我假設本文的讀者已經熟悉 npm 和 Yarn 建立的扁平 node_modules。如果你不了解 npm 3 為什麼必須在 v3 中開始使用扁平的 node_modules,你可以在 為什麼我們應該使用 pnpm? 中找到一些前因後果。

那麼,為什麼 pnpm 的 node_modules 不尋常?讓我們建立兩個目錄,並在其中一個目錄中執行 npm add express,在另一個目錄中執行 pnpm add express。以下是你在第一個目錄的 node_modules 中獲得的頂端

.bin
accepts
array-flatten
body-parser
bytes
content-disposition
cookie-signature
cookie
debug
depd
destroy
ee-first
encodeurl
escape-html
etag
express

您可以在此處查看整個目錄。

這是您在 pnpm 建立的 node_modules 中所獲得的資訊

.pnpm
.modules.yaml
express

您可以在此處查看。

那麼所有依賴項在哪裡?node_modules 中只有一個名為 .pnpm 的資料夾和一個名為 express 的符號連結。嗯,我們只安裝了 express,因此這是您的應用程式必須存取的唯一套件

在此處閱讀更多關於 pnpm 的嚴格性為何是一件好事

讓我們看看 express 中有什麼

▾ node_modules
▸ .pnpm
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md
.modules.yaml

express 沒有 node_modulesexpress 的所有依賴項在哪裡?

訣竅在於 express 只是一個符號連結。當 Node.js 解析依賴項時,它會使用它們的實際位置,因此它不會保留符號連結。但是您可能會問,express 的實際位置在哪裡?

在此處:node_modules/.pnpm/express@4.17.1/node_modules/express

好的,現在我們知道 .pnpm/ 資料夾的用途。.pnpm/ 將所有套件儲存在平面資料夾結構中,因此每個套件都可以在使用此模式命名的資料夾中找到

.pnpm/<name>@<version>/node_modules/<name>

我們稱之為虛擬儲存目錄。

此平面結構避免了由 npm v2 建立的巢狀 node_modules 所造成的長路徑問題,但與 npm v3,4,5,6 或 Yarn v1 建立的平面 node_modules 不同,它讓套件保持孤立。

現在讓我們深入了解 express 的實際位置

  ▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md

這是騙局嗎?它仍然缺少 node_modules!pnpm 的 node_modules 結構的第二個訣竅是套件的依賴項位於與依賴套件的實際位置相同的目錄層級上。因此 express 的依賴項不在 .pnpm/express@4.17.1/node_modules/express/node_modules/ 中,而是在.pnpm/express@4.17.1/node_modules/

▾ node_modules
▾ .pnpm
▸ accepts@1.3.5
▸ array-flatten@1.1.1
...
▾ express@4.16.3
▾ node_modules
▸ accepts
▸ array-flatten
▸ body-parser
▸ content-disposition
...
▸ etag
▾ express
▸ lib
History.md
index.js
LICENSE
package.json
Readme.md

express 的所有依賴項都是 node_modules/.pnpm/ 中適當目錄的符號連結。將 express 的依賴項放置在高一層級可以避免循環符號連結。

因此,正如您所見,即使 pnpm 的 node_modules 結構乍看之下似乎不尋常

  1. 它完全相容於 Node.js
  2. 套件與其依賴項分組良好

對於具有同儕依賴項的套件,結構稍微複雜一些,但概念相同:使用符號連結建立具有平面目錄結構的巢狀結構。