資料夾

npm 使用的資料夾結構

選擇 CLI 版本

說明

npm 會在您的電腦上放置各種東西。這是它的工作。

本文將告訴您它放置在哪裡。

tl;dr

  • 本機安裝(預設):將資料放置在目前套件根目錄的 ./node_modules 中。
  • 全域安裝(使用 -g):將資料放置在 /usr/local 或 node 安裝的任何位置。
  • 如果您要 require(),請將其安裝在本機
  • 如果您要在命令列上執行,請將其安裝在全域
  • 如果您需要同時安裝,請在兩個地方安裝,或使用 npm link

prefix 組態

預設 prefix 設定 為 node 安裝的位置。在大部分系統中,這是 /usr/local。在 Windows 中,這是 %AppData%\npm。在 Unix 系統中,由於 node 通常安裝在 {prefix}/bin/node 而不是 {prefix}/node.exe,因此會高一層。

global 旗標設定時,npm 會將項目安裝到此 prefix。當未設定時,它會使用目前套件的根目錄,或如果不在套件中,則使用目前工作目錄。

Node 模組

套件會放置在 prefix 下的 node_modules 資料夾中。在本地安裝時,這表示您可以 require("packagename") 來載入其主要模組,或 require("packagename/lib/path/to/sub/module") 來載入其他模組。

在 Unix 系統上的全域安裝會轉到 {prefix}/lib/node_modules。在 Windows 上的全域安裝會轉到 {prefix}/node_modules(也就是沒有 lib 資料夾)。

範圍套件的安裝方式相同,但它們會群組在一起,放在相關 node_modules 資料夾的子資料夾中,該子資料夾的名稱是範圍前綴,加上 @ 符號,例如 npm install @myorg/package 會將套件放置在 {prefix}/node_modules/@myorg/package。有關更多詳細資訊,請參閱 scope

如果您想 require() 套件,請在本地安裝它。

可執行檔

在全域模式中,可執行檔會連結到 Unix 上的 {prefix}/bin,或直接連結到 Windows 上的 {prefix}。確保路徑在您的終端的 PATH 環境中,才能執行它們。

在本地模式中,可執行檔會連結到 ./node_modules/.bin,以便讓它們可供透過 npm 執行的腳本使用。(例如,這樣一來,當您執行 npm test 時,測試執行器就會在路徑中。)

手冊頁

在全域模式中,手冊頁會連結到 {prefix}/share/man

在本地模式中,不會安裝手冊頁。

不會在 Windows 系統上安裝手冊頁。

快取

請參閱 npm cache。快取檔案儲存在 Posix 上的 ~/.npm,或 Windows 上的 %LocalAppData%/npm-cache

這由 cache 設定 參數控制。

暫存檔案

預設情況下,暫存檔案會儲存在由 tmp 設定 指定的資料夾中,預設為 TMPDIR、TMP 或 TEMP 環境變數,或 Unix 上的 /tmp 和 Windows 上的 c:\windows\temp

暫存檔案會在這個根目錄下獲得每個程式執行階段的唯一資料夾,並在成功結束時刪除。

更多資訊

在本地安裝時,npm 會先嘗試尋找適當的 prefix 資料夾。這是為了讓 npm install foo@1.2.3 安裝到您套件的合理根目錄,即使您碰巧 cd 到其他資料夾。

從 $PWD 開始,npm 會向上瀏覽資料夾樹狀結構,檢查包含 package.json 檔案或 node_modules 資料夾的資料夾。如果找到此類資料夾,則將其視為執行 npm 指令的有效「目前目錄」。(此行為受到 git 在工作目錄中執行 git 指令時尋找 .git 資料夾的邏輯啟發,且與其類似。)

如果找不到套件根目錄,則使用目前資料夾。

當您執行 npm install foo@1.2.3 時,套件會載入快取,然後解壓縮到 ./node_modules/foo。然後,foo 的任何相依套件也會以類似方式解壓縮到 ./node_modules/foo/node_modules/...

任何 bin 檔案都會連結到 ./node_modules/.bin/,以便 npm 指令在需要時可以找到它們。

全域安裝

如果 global 設定 設為 true,則 npm 會「全域」安裝套件。

對於全域安裝,套件的安裝方式大致相同,但會使用上述資料夾。

循環、衝突和資料夾簡約

循環會使用節點模組系統的特性來處理,它會向上瀏覽目錄尋找 node_modules 資料夾。因此,在每個階段,如果套件已安裝在祖先 node_modules 資料夾中,則不會在目前位置安裝。

考慮上述情況,其中 foo -> bar -> baz。假設除此之外,baz 還依賴於 bar,因此您會得到:foo -> bar -> baz -> bar -> baz ...。但是,由於資料夾結構為:foo/node_modules/bar/node_modules/baz,因此不需要將 bar 的另一個副本放入 .../baz/node_modules 中,因為當 baz 呼叫 require("bar") 時,它會取得安裝在 foo/node_modules/bar 中的副本。

此捷徑僅在多個巢狀 node_modules 資料夾中安裝完全相同的版本時使用。如果兩個「a」套件是不同版本,仍然有可能有 a/node_modules/b/node_modules/a。但是,在不重複完全相同的套件多次的情況下,將永遠防止無限迴歸。

另一個最佳化方式是將相依項安裝在最高層級,也就是在地化的「目標」資料夾 (hoisting) 底下。從版本 3 開始,npm 預設會 hoist 相依項。

範例

考慮這個相依項圖

foo
+-- blerg@1.2.5
+-- bar@1.2.3
| +-- blerg@1.x (latest=1.3.7)
| +-- baz@2.x
| | `-- quux@3.x
| | `-- bar@1.2.3 (cycle)
| `-- asdf@*
`-- baz@1.2.3
`-- quux@3.x
`-- bar

在這個情況下,我們預期會看到這樣的資料夾結構 (所有相依項都 hoist 到最高層級)

foo
+-- node_modules
+-- blerg (1.2.5) <---[A]
+-- bar (1.2.3) <---[B]
| +-- node_modules
| +-- baz (2.0.2) <---[C]
+-- asdf (2.3.4)
+-- baz (1.2.3) <---[D]
+-- quux (3.2.0) <---[E]

由於 foo 直接相依於 bar@1.2.3baz@1.2.3,因此會將這些相依項安裝在 foo 的 node_modules 資料夾中。

即使 blerg 的最新版本是 1.3.7,但 foo 特別相依於版本 1.2.5。因此,會將此版本安裝在 [A]。由於 blerg 的父層安裝滿足了 bar 對 blerg@1.x 的相依項,因此不會在 [B] 下安裝另一個副本。

Bar [B] 也相依於 baz 和 asdf。由於它相依於 baz@2.x,因此無法重複使用父層 node_modules 資料夾 [D] 中安裝的 baz@1.2.3,而必須安裝自己的副本 [C]。為了最小化重複,npm 預設會將相依項 hoist 到頂層,因此 asdf 會安裝在 [A] 下。

在 bar 下方,baz -> quux -> bar 相依項會產生一個循環。但是,由於 bar 已在 quux 的祖先 [B] 中,因此不會在該資料夾中解壓另一個 bar 副本。同樣地,quux 的 [E] 資料夾樹是空的,因為它對 bar 的相依項已由安裝在 [B] 的父層資料夾副本滿足。

若要取得各個項目安裝位置的圖形細目,請使用 npm ls

發布

在發布時,npm 會在 node_modules 資料夾中尋找。如果該資料夾中的任何項目不在 bundleDependencies 陣列中,則不會將這些項目包含在封裝 tarball 中。

這允許封裝維護者在本地安裝他們的所有相依項 (和開發相依項),但只重新發布無法在其他地方找到的那些項目。請參閱 package.json 以取得更多資訊。

另請參閱