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


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

 

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

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

NPM

npm是Node.js能夠如此成功的主要原因之一。npm團隊做了很多的工作,以確保npm保持向后兼容,並在不同的環境中保持一致。

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

給定一個版本號:主版本號.次版本號.補丁版本號, 以下這三種情況需要增加相應的版本號:

  • 主版本號: 當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/semver

理論上,次版本號的變化並不會影響向后兼容性。因此,安裝最新版的依賴庫應該是能正常工作的,而且能引入自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客戶端仍然可以做得很好。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM