跳到主要內容
版本:9.x

符號連結的 `node_modules` 結構

資訊

本文僅說明當沒有具有同儕相依性的套件時,pnpm 的 node_modules 如何結構化。對於具有同儕的相依性的更複雜情況,請參閱 如何解析同儕

pnpm 的 node_modules 佈局使用符號連結來建立相依性的巢狀結構。

node_modules 內每個套件的每個檔案都是指向內容可尋址儲存體的硬連結。假設你安裝了依賴於 bar@1.0.0foo@1.0.0。pnpm 會將兩個套件硬連結到 node_modules,如下所示

node_modules
└── .pnpm
├── bar@1.0.0
│ └── node_modules
│ └── bar -> <store>/bar
│ ├── index.js
│ └── package.json
└── foo@1.0.0
└── node_modules
└── foo -> <store>/foo
├── index.js
└── package.json

這些是 node_modules 中唯一的「真實」檔案。一旦所有套件都硬連結到 node_modules,就會建立符號連結來建構巢狀相依性圖形結構。

你可能已經注意到,兩個套件都硬連結到 node_modules 資料夾內的一個子資料夾(foo@1.0.0/node_modules/foo)。這是必要的,因為

  1. 允許套件匯入它們自己。foo 應該能夠 require('foo/package.json')import * as package from "foo/package.json"
  2. 避免循環符號連結。套件的相依性會放置在相依套件所在的資料夾中。對於 Node.js 來說,相依性在套件的 node_modules 內或父目錄中的任何其他 node_modules 中沒有差別。

安裝的下一階段是建立相依性的符號連結。bar 將會符號連結到 foo@1.0.0/node_modules 資料夾

node_modules
└── .pnpm
├── bar@1.0.0
│ └── node_modules
│ └── bar -> <store>/bar
└── foo@1.0.0
└── node_modules
├── foo -> <store>/foo
└── bar -> ../../bar@1.0.0/node_modules/bar

接下來,處理直接相依性。foo 將會符號連結到根目錄 node_modules 資料夾,因為 foo 是專案的相依性

node_modules
├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo
└── .pnpm
├── bar@1.0.0
│ └── node_modules
│ └── bar -> <store>/bar
└── foo@1.0.0
└── node_modules
├── foo -> <store>/foo
└── bar -> ../../bar@1.0.0/node_modules/bar

這是一個非常簡單的範例。但是,佈局將維持這個結構,不論相依性的數量和相依性圖形的深度為何。

讓我們新增 qar@2.0.0 作為 barfoo 的相依性。以下是新結構的樣子

node_modules
├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo
└── .pnpm
├── bar@1.0.0
│ └── node_modules
│ ├── bar -> <store>/bar
│ └── qar -> ../../qar@2.0.0/node_modules/qar
├── foo@1.0.0
│ └── node_modules
│ ├── foo -> <store>/foo
│ ├── bar -> ../../bar@1.0.0/node_modules/bar
│ └── qar -> ../../qar@2.0.0/node_modules/qar
└── qar@2.0.0
└── node_modules
└── qar -> <store>/qar

正如你所見,即使圖形現在更深(foo > bar > qar),檔案系統中的目錄深度仍然相同。

這個佈局乍看之下可能很奇怪,但它完全相容於 Node 的模組解析演算法!在解析模組時,Node 會忽略符號連結,因此當從 foo@1.0.0/node_modules/foo/index.js 載入 bar 時,Node 不會使用 foo@1.0.0/node_modules/bar 中的 bar,而是將 bar 解析到它的實際位置 (bar@1.0.0/node_modules/bar)。因此,bar 也可以解析其在 bar@1.0.0/node_modules 中的相依項。

這個佈局的一大好處是,只有相依項中實際存在的套件才能存取。使用扁平化的 node_modules 結構,所有提升的套件都可以存取。如需進一步瞭解為何這是一個優點,請參閱「pnpm 的嚴謹性有助於避免愚蠢的錯誤