[轉] 一文看懂npm、yarn、pnpm之間的區別

[From] http://geek.csdn.net/news/detail/197339html

 

原文:Understanding differences between npm, yarn and pnpm 
做者:Alex Kras 
翻譯:雁驚寒node

本文做者對比了當前主流的包管理工具npm、yarn、pnpm之間的區別,並提出了合適的使用建議,如下爲譯文:git

NPM

npm是Node.js可以如此成功的主要緣由之一。npm團隊作了不少的工做,以確保npm保持向後兼容,並在不一樣的環境中保持一致。github

npm是圍繞着語義版本控制(semver)的思想而設計的,下面是從他們的網站摘抄過來的:npm

給定一個版本號:主版本號.次版本號.補丁版本號, 如下這三種狀況須要增長相應的版本號:json

  • 主版本號: 當API發生改變,並與以前的版本不兼容的時候
  • 次版本號: 當增長了功能,可是向後兼容的時候
  • 補丁版本號: 當作了向後兼容的缺陷修復的時候

npm使用一個名爲package.json的文件,用戶能夠經過npm install --save命令把項目裏全部的依賴項保存在這個文件裏。緩存

例如,運行npm install --save lodash會將如下幾行添加到package.json文件中。安全

"dependencies": {
    "lodash": "^4.17.4"
}

請注意,在版本號lodash以前有個^字符。這個字符告訴npm,安裝主版本等於4的任意一個版本便可。因此若是我如今運行npm進行安裝,npm將安裝lodash的主版本爲4的最新版,多是 lodash@4.25.5(@是npm約定用來肯定包名的指定版本的)。你能夠在此處查看全部支持的字符:https://docs.npmjs.com/misc/semverbabel

理論上,次版本號的變化並不會影響向後兼容性。所以,安裝最新版的依賴庫應該是能正常工做的,並且能引入自4.17.4版本之後的重要錯誤和安全方面的修復。工具

可是,另外一方面,即便不一樣的開發人員使用了相同的package.json文件,在他們本身的機器上也可能會安裝同一個庫的不一樣種版本,這樣就會存在潛在的難以調試的錯誤和「在個人電腦上…」的情形。

大多數npm庫都嚴重依賴於其餘npm庫,這會致使嵌套依賴關係,並增長沒法匹配相應版本的概率。

雖然能夠經過npm config set save-exact true命令關閉在版本號前面使用^的默認行爲,但這個只會影響頂級依賴關係。因爲每一個依賴的庫都有本身的package.json文件,而在它們本身的依賴關係前面可能會有^符號,因此沒法經過package.json文件爲嵌套依賴的內容提供保證。

爲了解決這個問題,npm提供了shrinkwrap命令。此命令將生成一個npm-shrinkwrap.json文件,爲全部庫和全部嵌套依賴的庫記錄確切的版本。

然而,即便存在npm-shrinkwrap.json這個文件,npm也只會鎖定庫的版本,而不是庫的內容。即使npm如今也能阻止用戶屢次重複發佈庫的同一版本,可是npm管理員仍然具備強制更新某些庫的權力。

這是引用自shrinkwrap文檔的內容:

若是你但願鎖定包中的特定字節,好比是爲了保證能正確地從新部署或構建,那麼你應該在源代碼控制中檢查依賴關係,或者採起一些其餘的機制來校驗內容,而不是靠校驗版本。

npm 2會安裝每個包所依賴的全部依賴項。若是咱們有這麼一個項目,它依賴項目A,項目A依賴項目B,項目B依賴項目C,那麼依賴樹將以下所示:

node_modules
- package-A
-- node_modules
--- package-B
----- node_modules
------ package-C
-------- some-really-really-really-long-file-name-in-package-c.js

這個結構可能會很長。這對於基於Unix的操做系統來講只不過是一個小煩惱,但對於Windows來講倒是個破壞性的東西,由於有不少程序沒法處理超過260個字符的文件路徑名。

npm 3採用了扁平依賴關係樹來解決這個問題,因此咱們的3個項目結構如今看起來以下所示:

node_modules
- package-A
- package-B
- package-C
-- some-file-name-in-package-c.js

這樣,一個原來很長的文件路徑名就從./node_modules/package-A/node_modules/package-B/node-modules/some-file-name-in-package-c.js變成了/node_modules/some-file-name-in-package-c.js

你能夠在這裏閱讀到更多有關NPM 3依賴解析的工做原理。

這種方法的缺點是,npm必須首先遍歷全部的項目依賴關係,而後再決定如何生成扁平的node_modules目錄結構。npm必須爲全部使用到的模塊構建一個完整的依賴關係樹,這是一個耗時的操做,是npm安裝速度慢的一個很重要的緣由

因爲我沒有詳細瞭解npm的變化,因此我想固然的覺得每次運行npm install命令時,NPM都得從互聯網上下載全部內容。

可是,我錯了,npm是有本地緩存的,它保存了已經下載的每一個版本的壓縮包。本地緩存的內容能夠經過npm cache ls命令進行查看。本地緩存的設計有助於減小安裝時間。

總而言之,npm是一個成熟、穩定、而且有趣的包管理器。

Yarn

Yarn發佈於2016年10月,並在Github上迅速擁有了2.4萬個Star。而npm只有1.2萬個Star。這個項目由一些高級開發人員維護,包括了Sebastian McKenzie(Babel.js)和Yehuda Katz(Ember.jsRustBundler等)。

從我搜集到的狀況來看,Yarn一開始的主要目標是解決上一節中描述的因爲語義版本控制而致使的npm安裝的不肯定性問題。雖然可使用npm shrinkwrap來實現可預測的依賴關係樹,但它並非默認選項,而是取決於全部的開發人員知道而且啓用這個選項。

Yarn採起了不一樣的作法。每一個yarn安裝都會生成一個相似於npm-shrinkwrap.jsonyarn.lock文件,並且它是默認建立的。除了常規信息以外,yarn.lock文件還包含要安裝的內容的校驗和,以確保使用的庫的版本相同。

因爲yarn是嶄新的通過從新設計的npm客戶端,它能讓開發人員並行化處理全部必須的操做,並添加了一些其餘改進,這使得運行速度獲得了顯著的提高,整個安裝時間也變得更少。我估計,速度提高是yarn受歡迎的主要緣由。

像npm同樣,yarn使用本地緩存。與npm不一樣的是,yarn無需互聯網鏈接就能安裝本地緩存的依賴項,它提供了離線模式。這個功能在2012年的npm項目中就被提出來過,但一直沒有實現。

yarn還提供了一些其餘改進,例如,它容許合併項目中使用到的全部的包的許可證,這一點讓人很高興。

一個有趣的事情是,yarn文檔的態度開始針對npm發生改變,由於yarn項目變得流行起來。

最開始的yarn公告是這麼介紹yarn的安裝的:

*最簡單的入門方法是運行: 
npm install -g yarn 
yarn*

如今的yarn安裝頁面是這麼說的:

注意:一般狀況下不建議經過npm進行安裝。npm安裝是非肯定性的,程序包沒有簽名,而且npm除了作了基本的SHA1哈希以外不執行任何完整性檢查,這給安裝系統程序帶來了安全風險。

基於這些緣由,強烈建議你經過最適合於你的操做系統的安裝方法來安裝yarn。

以這種速度發展下去的話,若是yarn要宣佈他們本身的registry,讓開發者慢慢淘汰npm的話,咱們一點都不會感到驚訝。

看起來彷佛要感謝yarn,npm終於意識到他們須要更加關注一些你們強烈要求的問題了。當我在審覈我以前提到的強烈要求的「離線」功能時,我注意到這個需求正在被積極地修復之中。

pnpm

正如我所提到的,在pnpm的做者Zoltan Kochan發表了「爲何要用pnpm?」以後,我才知道pnpm。

我不會介紹太多的細節(由於這篇文章已經發布好久了),可是你能夠查看個人最初的帖子來尋找更多的內容,同時在Twitter上加入討論

可是

我想指出的是,pnpm運行起來很是的快,甚至超過了npm和yarn

爲何這麼快呢? 由於它採用了一種巧妙的方法,利用硬連接和符號連接來避免複製全部本地緩存源文件,這是yarn的最大的性能弱點之一。

使用連接並不容易,會帶來一堆問題須要考慮。

正如Sebastian在Twitter上指出的那樣,他最初是打算在yarn中使用符號連接的,可是因爲其餘一些緣由放棄了它。

同時,正如在Github上擁有2000多個Star那樣,pnpm可以爲許多人所用。

此外,截至2017年3月,它繼承了yarn的全部優勢,包括離線模式和肯定性安裝。

總結

我認爲yarn和pnpm的開發人員作了一個驚人的工做。我我的喜歡的是肯定性安裝,由於我喜歡控制,我不喜歡驚喜。

不管這場競爭的結果是什麼,我很感謝yarn在npm的腳下點了一把火,提供了另一個選擇。

我確信yarn是一個更安全的選擇,可是pnpm多是一些測試用例的更好的選擇。例如,它能夠在運行大量集成測試並但願儘量快地安裝依賴關係的中小型團隊中發揮做用。

最後,我認爲,npm仍然提供了一個很是有用的解決方案,支持大量的測試用例。大多數開發人員使用原始npm客戶端仍然能夠作得很好。

相關文章
相關標籤/搜索