爲何咱們應該使用 pnpm(譯)

pnpm 是又一個 Node.js 包管理工具。它能夠替換 npm, 並且 npm 更快更高效。html

能有多快? 3 倍! 能夠在這裏查看 benchmarks 。node

爲何更高效? 當你安裝一個軟件包,咱們把它保存在你的機器上的一個全局存儲目錄中,而後咱們建立一個硬連接而不是複製。 對於模塊的每一個版本,只會有一個副本保存在磁盤上。 例如,當使用 npm 或 yarn 時,若是有 100 個使用 lodash 的項目,你的磁盤上就會有有 100 份 lodash 的拷貝。pnpm 能幫助您節省千兆字節的磁盤空間!git

爲何不用 Yarn

老實說,當 Yarn 開始公開時,我真的很失望。 幾個月來我一直在爲 pnpm 做出重大貢獻,並且沒有任何關於 Yarn 的消息。 有關其發展的信息是不公開的。github

幾天以後,我意識到 Yarn 只是 npm 的一個小小的改進。 儘管它使得安裝速度更快,而且具備一些不錯的新功能,可是它使用了與 npm 相同的扁平 node_modules 結構(從版本 3 開始)。算法

扁平化的依賴關係樹帶來了一系列的問題:shell

  1. 模塊能夠訪問他們不依賴的軟件包 (注:本人使用pnpm替代npm後有些依賴必須顯式安裝)
  2. 扁平化依賴樹的算法至關複雜
  3. 一些軟件包必須複製在一個項目的 node_modules 文件夾中

此外,還有一些 Yarn 不打算解決的問題,如磁盤空間使用問題。 因此我決定繼續把時間花在 pnpm 上,並取得了巨大的成功。 截至目前(2017 年 3 月),pnpm 具備 Yarn 超過 npm 的全部附加功能:npm

  1. 安全 。 像 Yarn 同樣,pnpm 有一個特殊的文件,其中包含全部安裝包的校驗碼,以在代碼執行以前驗證每一個已安裝包的完整性。
  2. 離線模式 。 pnpm 將全部下載的軟件包 tar 包保存在本地鏡像倉庫中。 當一個包在本地可用時,它從不發出請求。 使用 --offline 參數,HTTP 請求能夠被徹底禁止。
  3. 速度 。 pnpm 不只比 npm 快,並且比 Yarn 還要快。 它比 cold 和 hot 緩存 Yarn 都快。 Yarn 從緩存拷貝文件,而 pnpm 只是從全局存儲目錄連接它們。

這怎麼可能?

正如我前面提到的,pnpm 不會拍平依賴關係樹。 所以,pnpm 使用的算法能夠更容易! 這就是爲何只有一名開發人員可以跟上 Yarn 的幾十位貢獻者的步伐。json

那麼,若是不依靠拍平的方式,pnpm 如何構造 node_modules 目錄呢? 爲了理解它,咱們應該回憶在 npm 版本 3 以前 node_modules 文件夾看起來是怎樣的。在 npm@3 以前,node_modules 結構是可預測和乾淨的,由於 node_modules 中的每一個依賴項都有本身的 node_modules 以及所包含依賴關係的 package.json 文件。緩存

node_modules
└─ foo
   ├─ index.js
   ├─ package.json
   └─ node_modules
      └─ bar
         ├─ index.js
         └─ package.json

這種方法有兩個嚴重的問題:安全

  • 頻繁使用的代碼包建立了太深的依賴關係樹,致使 Windows 上很長的目錄路徑問題
  • 當被不一樣的依賴關係須要時,代碼包會被複制粘貼屢次

爲了解決這些問題,npm 從新思考了 node_modules 結構,並提出了扁平化。 在 npm@3 中,node_modules 的結構如今看起來像這樣:

node_modules
├─ foo
|  ├─ index.js
|  └─ package.json
└─ bar
   ├─ index.js
   └─ package.json

有關 npm v3 依賴關係解析的更多信息,請參見 npm v3 依賴關係解析

與 npm@3 不一樣,pnpm 試圖解決 npm@2 所具備的問題,而不是將依賴關係樹展平。 在由 pnpm 建立的 node_modules 文件夾中,全部的軟件包都有本身的依賴關係,可是目錄樹永遠不會像 npm@2 那麼深。 pnpm 保持全部依賴關係平坦,但使用符號連接將它們組合在一塊兒。

-> - a symlink (or junction on Windows)

node_modules
├─ foo -> .registry.npmjs.org/foo/1.0.0/node_modules/foo
└─ .registry.npmjs.org
   ├─ foo/1.0.0/node_modules
   |  ├─ bar -> ../../bar/2.0.0/node_modules/bar
   |  └─ foo
   |     ├─ index.js
   |     └─ package.json
   └─ bar/2.0.0/node_modules
      └─ bar
         ├─ index.js
         └─ package.json

要查看實例,請訪問 示例 pnpm 項目

雖然這個例子對於一個小項目彷佛太複雜了,可是對於更大的項目來講,結構看起來比 npm / yarn 建立的結構要好。 讓咱們看看爲何它不錯。

首先,您可能已經注意到,node_modules 根目錄下的包只是一個符號連接。 這很好,由於 Node.js 忽略符號連接並執行實際路徑。 因此 require('foo')會執行文件 node_modules/.registry.npmjs.org/foo/1.0.0/node_modules/foo/index.js 而不是 node_modules/foo/index.js

其次,沒有一個安裝的軟件包在其目錄中有本身的 node_modules 文件夾。 那麼 foo 怎麼引入 bar? 讓咱們看看包含 foo 包的文件夾:

node_modules/.registry.npmjs.org/foo/1.0.0/node_modules
├─ bar -> ../../bar/2.0.0/node_modules/bar
└─ foo
   ├─ index.js
   └─ package.json

如您所看到的

  1. foo 的依賴關係(只有 bar)被安裝,但在目錄結構中的一級。
  2. 這兩個軟件包都位於名爲 node_modules 的文件夾內。

foo 能夠引入 bar,由於 Node.js 在目錄結構中查找模塊直到磁盤的根目錄。 並且 foo 也能夠引入 foo,由於它在一個名爲 node_modules 的文件夾中(沒錯,這正是一些軟件包所作的)。

你相信嗎?

只需經過 npm 安裝 pnpm:npm install -g pnpm。 只要你想安裝一些東西,就用它來代替 npm:pnpm i foo。

您也能夠在 pnpm GitHub repopnpm.js.org 中閱讀更多信息。 您能夠關注 pnpm on Twitter,或者在 pnpm Gitter Chat Room 尋求幫助。


原文:Why should we use pnpm?

相關文章
相關標籤/搜索