本篇文章帶大家了解一下三種JavaScript包管理器(npm、yarn、pnpm),并將這三種包管理器進(jìn)行對比,聊聊npm、yarn、pnpm三者的區(qū)別和關(guān)聯(lián),希望對大家有所幫助,如有問題歡迎指出!
包管理器領(lǐng)域的三個主要參與者:
-
npm
-
Yarn
-
高性能 npm (pnpm)
實際上我們已經(jīng)在所有包管理器中實現(xiàn)了基本相似的功能,因此您很可能會根據(jù)非功能性要求來決定使用哪個包管理器,例如安裝速度、存儲消耗或?qū)嶋H情況。
當(dāng)然,您選擇使用每個包管理器的方式會有所不同,但它們都有基本一致的概念。以上這些包管理器都可以執(zhí)行以下指令:
- 讀寫數(shù)據(jù)
- 批量安裝或更新所有依賴項
- 添加、更新和刪除依賴項
- 運(yùn)行腳本
- 發(fā)布包
然而盡管如此,包管理器在底層還是有所不同的。傳統(tǒng)上 npm
和 Yarn
將依賴項安裝在一個平鋪的node_modules文件夾中。(這里注意先后順序,是 yarn
先平鋪的,之前 npm
是遞歸)。但是平鋪也會造成一系列的安全問題。
依賴結(jié)構(gòu)的不確定性。
扁平化算法本身的復(fù)雜性很高,耗時較長。
項目中仍然可以非法訪問
有聲明過依賴的包
因此,pnpm
在 node_modules
文件夾中引入了一些新概念來更高效的存儲依賴,。Yarn Berry
甚至通過完全放棄 node_modules
的 (PnP) 模式(另一個文章會具體說明)來走得更遠(yuǎn)。
JavaScript package簡史
最早發(fā)布的包管理器是 npm
,早在 2010 年 1 月。它就確立了今天包管理器工作的核心原則。但是既然 npm
已經(jīng)存在 10 多年了,為什么還有其他選擇?以下是出現(xiàn)這種情況的一些關(guān)鍵原因:
node_modules
文件夾結(jié)構(gòu)的依賴關(guān)系解析算法不同(嵌套 & 平鋪、node_modules
vs. PnP mode)- 依賴提升方式不同(
hoisting
) locking
格式不同(性能都不同,比如yarn
自己寫的那一套)- 磁盤存儲包文件方式不同(空間效率不同)
- 多包項目(又名
workspaces
)的支持不同,這會影響monorepos
的可維護(hù)性和速度 - 新工具和命令的需求不同(通過插件和社區(qū)工具對可擴(kuò)展性的需求不同)
- 可配置性和靈活性不同
讓我們深入了解一下 npm
崛起后這些方面如何確定的歷史,Yarn Classic
如何解決其中的一些問題,pnpm
如何擴(kuò)展這些概念,以及 Yarn Berry
作為 Yarn Classic
的繼任者如何打破這些傳統(tǒng)的概念和流程。
先驅(qū)者 npm
npm
是包管理器的鼻祖。許多人錯誤地認(rèn)為 npm
是“Node package manager”的首字母縮寫詞,但事實并非如此。
它的發(fā)布構(gòu)成了一場革命,因為在此之前,項目依賴項都是手動下載和管理的。npm
引入了諸如文件及其元數(shù)據(jù)字段、將依賴項存儲在node_modules
, 自定義腳本, 公共和私有包等等。
2020 年,GitHub 收購了 npm,所以原則上 npm
現(xiàn)在歸微軟管理。在撰寫本文時,最新的主要版本是 v8,于 2021 年 10 月發(fā)布。
創(chuàng)新者 Yarn Classic
在 2016 年 10 月,F(xiàn)acebook 宣布與 Google 和其他一些公司合作開發(fā)一個新的包管理器(engineering.fb.com/2016/10/11/…),以解決 npm 當(dāng)時存在的一致性、安全性和性能問題。他們將替代品命名為Yarn。
盡管 Yarn
還是基于 npm
的許多概念和流程來架構(gòu)設(shè)計的,但 Yarn
還是對包管理器領(lǐng)域產(chǎn)生了重大影響。與 npm
相比,Yarn
并行化操作以加快安裝過程,這一直是 npm
早期版本的主要痛點(diǎn)。
Yarn
為讀寫、安全性和性能設(shè)定了更高的標(biāo)準(zhǔn),還發(fā)明了許多概念(后來npm
也為此做了很多改進(jìn)),包括:
monorepo
支持- 緩存安裝
- 離線下載
- 文件鎖(
Locking
)
Yarn v1 于 2020 年進(jìn)入維護(hù)模式 。從那時起,v1.x 系列被認(rèn)為是舊版,并更名為 Yarn Classic
。它的繼任者 Yarn v2 (Berry) 現(xiàn)在是更加活躍的開發(fā)分支。
更高效的pnpm
pnpm
的第 1 版由 Zoltan Kochan于 2017 年發(fā)布。它是 npm
的替代品,所以如果你有一個 npm
項目,你可以馬上使用 pnpm
!
創(chuàng)建 pnpm
的主要原因是 npm
和 Yarn
對于跨項目使用的依賴項存儲結(jié)構(gòu)非常冗余。盡管 Yarn Classic
比 npm
具有速度優(yōu)勢,但它使用相同的依賴解析方法,這對 pnpm
來說是不行的:npm
和 Yarn Classic
使用 hoisting
來平鋪他們的 node_modules
.
pnpm
沒有優(yōu)化之前的結(jié)構(gòu),而是引入了另一種依賴解決策略:內(nèi)容尋址的一種存儲結(jié)構(gòu)。此方法生成的 node_modules
文件夾其實是依賴于全局存儲在主文件夾上的 ~/.pnpm-store/
目錄。每個版本的依賴項都物理形式存儲在該目錄文件夾中一次,構(gòu)成單一的源地址來節(jié)省相當(dāng)多的磁盤空間。
node_modules
結(jié)構(gòu)是通過使用 symlinks
創(chuàng)建依賴關(guān)系的嵌套結(jié)構(gòu)(其中文件夾內(nèi)每個文件/包都是通過硬鏈接存儲)官方文檔中的下圖闡明了這一點(diǎn)。(待填坑:軟硬鏈接)
2021 年報告中可見 pnpm
的影響力:因為他們在內(nèi)容可尋址存儲方面的創(chuàng)新,競爭對手都希望采用 pnpm
的概念,比如象征性鏈接的結(jié)構(gòu)和包的高效磁盤管理。
Yarn (v2, Berry),用 Plug'n'Play 重新發(fā)明的輪子
Yarn 2于 2020 年 1 月發(fā)布,被宣傳為原始 Yarn
的重大升級。Yarn
團(tuán)隊將其稱為 Yarn Berry
以更明顯地表明它本質(zhì)上是一個具有新的代碼庫和新的原則規(guī)范的新包管理器。
Yarn Berry
的主要創(chuàng)新是其即插即用 (PnP)方法,它是作為修復(fù)node_modules的策略。不是生成node_modules
的策略,而是生成一個帶有依賴查找表的文件 .pnp.cjs
,因為它是單個文件而不是嵌套的文件夾結(jié)構(gòu),所以可以更有效地處理依賴。此外,每個包都以zip 文件的形式存儲在文件夾內(nèi)來替代 .yarn/cache/
,占用的磁盤空間也比 node_modules
少。
所有這些變化如此之快以至于在發(fā)布后引起了很大的爭議。PnP 這種破壞性的重大更改要求維護(hù)者更新他們現(xiàn)有的包以便與其兼容。默認(rèn)情況下使用全新的 PnP 方法并且恢復(fù)到 node_modules
最初并不簡單,這導(dǎo)致許多知名開發(fā)人員沒有加入其中的考慮且公開批評 Yarn 2。
此后,Yarn Berry
團(tuán)隊在其后續(xù)版本中解決了許多問題。為了解決 PnP 的不兼容問題,團(tuán)隊提供了方法來輕松更改默認(rèn)操作模式。在node_modules插件的幫助下,切換回傳統(tǒng) node_modules
方法只需要一行配置。
此外,隨著時間的推移,JavaScript 生態(tài)系統(tǒng)為 PnP 提供了越來越多的支持,正如您在此兼容性表中所見,一些大型項目已經(jīng)開始采用 Yarn Berry
。
盡管 Yarn Berry
還很年輕,但它也已經(jīng)對包管理器領(lǐng)域產(chǎn)生了影響——pnpm
在 2020 年末采用了PnP 方法。
安裝工作流程
首先必須在每個開發(fā)人員的本地和 CI/CD 系統(tǒng)上安裝包管理器。
npm
npm
與 Node.js
一起提供,因此不需要額外的步驟。除了為您的操作系統(tǒng)下載Node.js 安裝程序外,使用 CLI 工具管理軟件版本已成為一種常見做法。在 Node 的上下文中,Node Version Manager (nvm) 或 Volta 已成為非常方便的實用程序。
Yarn Classic 和 Yarn Berry
您可以通過不同的方式安裝 Yarn 1,例如,作為 npm
包來安裝:.$ npm i -g yarn
要從Yarn Classic 遷移到 Yarn Berry,推薦的方法是:
-
安裝或更新
Yarn Classic
到最新的版本 -
使用命令升級到最新的現(xiàn)代版本
yarn set version berry
但是,在此推薦的安裝 Yarn Berry方法是通過 Corepack。
Corepack是由 Yarn Berry 的開發(fā)者創(chuàng)建的。該計劃最初被命名為包管理器管理器(pmm) ?,并在 LTS v16 中與 Node 合并。
在 Corepack 的幫助下,因為 Node 包含 Yarn Classic
、Yarn Berry
和 pnpm
二進(jìn)制文件所以您不必“單獨(dú)”安裝的 npm
的替代包管理器。這些墊片允許用戶運(yùn)行 Yarn 和 pnpm 命令而無需先顯式安裝它們,也不會弄亂 Node 發(fā)行版。
Corepack 預(yù)裝了 Node.js ≥ v16.9.0。但是,對于較舊的 Node 版本,您可以使用⬇️
npm install -g corepack
在使用之前先啟用 Corepack。該示例顯示了如何在 Yarn Berry v3.1.1 中激活它。
# you need to opt-in first $ corepack enable # shim installed but concrete version needs to activated $ corepack prepare yarn@3.1.1 --activate
pnpm
您可以將 pnpm
作為 npm
包來安裝: $ npm i -g pnpm
。您還可以使用 Corepack 安裝 pnpm :
$ corepack prepare pnpm@6.24.2 --activate
項目結(jié)構(gòu)
在本節(jié)中,您將一目了然地看到不同包管理器的主要特征。您可以輕松發(fā)現(xiàn)配置特定包管理器涉及哪些文件,以及哪些文件是由安裝步驟生成的。
所有包管理器都將所有重要的元信息存儲在項目清單package.json文件中。 此外,根級別的配置文件可以被用來設(shè)置不同的私有包或者不同的依賴項解析配置。
在安裝步驟中,依賴項 dependencies
被存儲在文件結(jié)構(gòu)中,例如 node_modules
并生成鎖定文件 locking
。本節(jié)不考慮工作區(qū)設(shè)置,因此所有示例僅顯示存儲依賴項的單個位置。
npm
使用$ npm install
或較短的 $ npm i
會生成一個 package-lock.json
文件和一個 node_modules
文件夾。還有 .npmrc
這種可配置的文件可以放在根級別目錄里面。有關(guān) locking
文件的