符號連結的 `node_modules` 結構
本文僅說明當沒有具有同儕相依性的套件時,pnpm 的 node_modules
如何結構化。對於具有同儕的相依性的更複雜情況,請參閱 如何解析同儕。
pnpm 的 node_modules
佈局使用符號連結來建立相依性的巢狀結構。
node_modules
內每個套件的每個檔案都是指向內容可尋址儲存體的硬連結。假設你安裝了依賴於 bar@1.0.0
的 foo@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
)。這是必要的,因為
- 允許套件匯入它們自己。
foo
應該能夠require('foo/package.json')
或import * as package from "foo/package.json"
。 - 避免循環符號連結。套件的相依性會放置在相依套件所在的資料夾中。對於 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
作為 bar
和 foo
的相依性。以下是新結構的樣子
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 的嚴謹性有助於避免愚蠢的錯誤」