這篇文章主要講解了“JavaScript包管理器實(shí)例比較分析”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“JavaScript包管理器實(shí)例比較分析”吧!
10年積累的成都網(wǎng)站制作、成都做網(wǎng)站經(jīng)驗(yàn),可以快速應(yīng)對客戶對網(wǎng)站的新想法和需求。提供各種問題對應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識你,你也不認(rèn)識我。但先制作網(wǎng)站后付款的網(wǎng)站建設(shè)流程,更有元寶免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
包管理器領(lǐng)域的三個主要參與者:
npm
Yarn
高性能 npm (pnpm)
實(shí)際上我們已經(jīng)在所有包管理器中實(shí)現(xiàn)了基本相似的功能,因此您很可能會根據(jù)非功能性要求來決定使用哪個包管理器,例如安裝速度、存儲消耗或?qū)嶋H情況。
當(dāng)然,您選擇使用每個包管理器的方式會有所不同,但它們都有基本一致的概念。以上這些包管理器都可以執(zhí)行以下指令:
讀寫數(shù)據(jù)
批量安裝或更新所有依賴項(xiàng)
添加、更新和刪除依賴項(xiàng)
運(yùn)行腳本
發(fā)布包
然而盡管如此,包管理器在底層還是有所不同的。傳統(tǒng)上 npm
和 Yarn
將依賴項(xiàng)安裝在一個平鋪的node_modules文件夾中。(這里注意先后順序,是 yarn
先平鋪的,之前 npm
是遞歸)。但是平鋪也會造成一系列的安全問題。
依賴結(jié)構(gòu)的不確定性。
扁平化算法本身的復(fù)雜性很高,耗時較長。
項(xiàng)目中仍然可以非法訪問
有聲明過依賴的包
因此,pnpm
在 node_modules
文件夾中引入了一些新概念來更高效的存儲依賴,。Yarn Berry
甚至通過完全放棄 node_modules
的 (PnP) 模式(另一個文章會具體說明)來走得更遠(yuǎn)。
最早發(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
自己寫的那一套)
磁盤存儲包文件方式不同(空間效率不同)
多包項(xiàng)目(又名 workspaces
)的支持不同,這會影響 monorepos
的可維護(hù)性和速度
新工具和命令的需求不同(通過插件和社區(qū)工具對可擴(kuò)展性的需求不同)
可配置性和靈活性不同
讓我們深入了解一下 npm
崛起后這些方面如何確定的歷史,Yarn Classic
如何解決其中的一些問題,pnpm
如何擴(kuò)展這些概念,以及 Yarn Berry
作為 Yarn Classic
的繼任者如何打破這些傳統(tǒng)的概念和流程。
npm
是包管理器的鼻祖。許多人錯誤地認(rèn)為 npm
是“Node package manager”的首字母縮寫詞,但事實(shí)并非如此。
它的發(fā)布構(gòu)成了一場革命,因?yàn)樵诖酥?,?xiàng)目依賴項(xiàng)都是手動下載和管理的。npm
引入了諸如文件及其元數(shù)據(jù)字段、將依賴項(xiàng)存儲在node_modules
, 自定義腳本, 公共和私有包等等。
2020 年,GitHub 收購了 npm,所以原則上 npm
現(xiàn)在歸微軟管理。在撰寫本文時,最新的主要版本是 v8,于 2021 年 10 月發(fā)布。
在 2016 年 10 月,F(xiàn)acebook 宣布與 Google 和其他一些公司合作開發(fā)一個新的包管理器(engineering.fb.com/2016/10/11/…),以解決 npm 當(dāng)時存在的一致性、安全性和性能問題。他們將替代品命名為Yarn。
盡管 Yarn
還是基于 npm
的許多概念和流程來架構(gòu)設(shè)計(jì)的,但 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
項(xiàng)目,你可以馬上使用 pnpm
!
創(chuàng)建 pnpm
的主要原因是 npm
和 Yarn
對于跨項(xiàng)目使用的依賴項(xiàng)存儲結(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
文件夾其實(shí)是依賴于全局存儲在主文件夾上的 ~/.pnpm-store/
目錄。每個版本的依賴項(xiàng)都物理形式存儲在該目錄文件夾中一次,構(gòu)成單一的源地址來節(jié)省相當(dāng)多的磁盤空間。
node_modules
結(jié)構(gòu)是通過使用 symlinks
創(chuàng)建依賴關(guān)系的嵌套結(jié)構(gòu)(其中文件夾內(nèi)每個文件/包都是通過硬鏈接存儲)官方文檔中的下圖闡明了這一點(diǎn)。(待填坑:軟硬鏈接)
2021 年報(bào)告中可見 pnpm
的影響力:因?yàn)樗麄冊趦?nèi)容可尋址存儲方面的創(chuàng)新,競爭對手都希望采用 pnpm
的概念,比如象征性鏈接的結(jié)構(gòu)和包的高效磁盤管理。
Yarn 2于 2020 年 1 月發(fā)布,被宣傳為原始 Yarn
的重大升級。Yarn
團(tuán)隊(duì)將其稱為 Yarn Berry
以更明顯地表明它本質(zhì)上是一個具有新的代碼庫和新的原則規(guī)范的新包管理器。
Yarn Berry
的主要創(chuàng)新是其即插即用 (PnP)方法,它是作為修復(fù)node_modules的策略。不是生成node_modules
的策略,而是生成一個帶有依賴查找表的文件 .pnp.cjs
,因?yàn)樗菃蝹€文件而不是嵌套的文件夾結(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)隊(duì)在其后續(xù)版本中解決了許多問題。為了解決 PnP 的不兼容問題,團(tuán)隊(duì)提供了方法來輕松更改默認(rèn)操作模式。在node_modules插件的幫助下,切換回傳統(tǒng) node_modules
方法只需要一行配置。
此外,隨著時間的推移,JavaScript 生態(tài)系統(tǒng)為 PnP 提供了越來越多的支持,正如您在此兼容性表中所見,一些大型項(xiàng)目已經(jīng)開始采用 Yarn Berry
。
盡管 Yarn Berry
還很年輕,但它也已經(jīng)對包管理器領(lǐng)域產(chǎn)生了影響——pnpm
在 2020 年末采用了PnP 方法。
首先必須在每個開發(fā)人員的本地和 CI/CD 系統(tǒng)上安裝包管理器。
npm
與 Node.js
一起提供,因此不需要額外的步驟。除了為您的操作系統(tǒng)下載Node.js 安裝程序外,使用 CLI 工具管理軟件版本已成為一種常見做法。在 Node 的上下文中,Node Version Manager (nvm) 或 Volta 已成為非常方便的實(shí)用程序。
您可以通過不同的方式安裝 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)建的。該計(jì)劃最初被命名為包管理器管理器(pmm) ?,并在 LTS v16 中與 Node 合并。
在 Corepack 的幫助下,因?yàn)?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
作為 npm
包來安裝: $ npm i -g pnpm
。您還可以使用 Corepack 安裝 pnpm :
$ corepack prepare pnpm@6.24.2 --activate
在本節(jié)中,您將一目了然地看到不同包管理器的主要特征。您可以輕松發(fā)現(xiàn)配置特定包管理器涉及哪些文件,以及哪些文件是由安裝步驟生成的。
所有包管理器都將所有重要的元信息存儲在項(xiàng)目清單package.json文件中。 此外,根級別的配置文件可以被用來設(shè)置不同的私有包或者不同的依賴項(xiàng)解析配置。
在安裝步驟中,依賴項(xiàng) dependencies
被存儲在文件結(jié)構(gòu)中,例如 node_modules
并生成鎖定文件 locking
。本節(jié)不考慮工作區(qū)設(shè)置,因此所有示例僅顯示存儲依賴項(xiàng)的單個位置。
使用$ npm install
或較短的 $ npm i
會生成一個 package-lock.json
文件和一個 node_modules
文件夾。還有 .npmrc
這種可配置的文件可以放在根級別目錄里面。有關(guān) locking
文件的更多信息,請參閱下一節(jié)。
. ├── node_modules/ ├── .npmrc ├── package-lock.json └── package.json
運(yùn)行 $ yarn
會創(chuàng)建一個 yarn.lock
文件和一個 node_modules
文件夾。.yarnrc
文件也可以是配置的選項(xiàng),Yarn Classic
也支持 .npmrc
文件。或者可以使用緩存文件夾 .yarn/cache/
和本地存儲的最近的 Yarn Classic
版本 .yarn/releases/
。
. ├── .yarn/ │ ├── cache/ │ └── releases/ │ └── yarn-1.22.17.cjs ├── node_modules/ ├── .yarnrc ├── package.json └── yarn.lock
因?yàn)檫@種特殊的安裝模式,比使用其他包管理器您必須在 Yarn Berry
項(xiàng)目中處理更多的文件和文件夾。有些是可選的,有些是強(qiáng)制性的。
Yarn Berry
不再支持 .npmrc
或者 .yarnrc
;他需要一個 .yarnrc.yml。對于傳統(tǒng)的生成 node_modules
文件夾的工作流程,您必須提供 nodeLinker
配置來使用 node_modules
或者 pnpm
的配置(這塊沒看懂)。
# .yarnrc.yml nodeLinker: node-modules # or pnpm
運(yùn)行 $ yarn
會將所有依賴項(xiàng)安裝在一個 node_modules
文件夾中。并且生成一個 yarn.lock
文件,該文件較新但與 Yarn Classic
不兼容。此外,還會生成一個用于離線安裝的 .yarn/cache/
文件夾。該文件夾是可選的,用于存儲項(xiàng)目使用的 Yarn Berry
版本。
. ├── .yarn/ │ ├── cache/ │ └── releases/ │ └── yarn-3.1.1.cjs ├── node_modules/ ├── .yarnrc.yml ├── package.json └── yarn.lock
無論是對于PnP 的嚴(yán)格模式還是松散模式,跟著 .pnp.cjs
和 yarn.lock
來執(zhí)行 $ yarn
都會生成一個 .yarn/cache/
還有 .yarn/unplugged
。PnP strict 是默認(rèn)模式,如果想要配置 loose 模式,需要如下形式開啟??:
# .yarnrc.yml nodeLinker: pnp pnpMode: loose
在 PnP 項(xiàng)目中,除了 releases
文件夾之外,.yarn
文件夾很可能還包含一個提供IDE 支持的 sdk/
文件夾。根據(jù)您的用例,.yarn
甚至可以包含更多的文件夾。
. ├── .yarn/ │ ├── cache/ │ ├── releases/ │ │ └── yarn-3.1.1.cjs │ ├── sdk/ │ └── unplugged/ ├── .pnp.cjs ├── .pnp.loader.mjs ├── .yarnrc.yml ├── package.json └── yarn.lock`
和 npm
或 Yarn Classic
項(xiàng)目的初始狀態(tài)一樣,pnpm
也需要 package.json
文件。使用 $ pnpm i
安裝依賴項(xiàng)后,會生成一個 node_modules
文件夾,但由于其內(nèi)容是可尋址存儲方式,其結(jié)構(gòu)完全不同。
pnpm
還會生成自己的鎖定文件 pnp-lock.yml
。 您可以使用可選文件 .npmrc
提供附加配置。
. ├── node_modules/ │ └── .pnpm/ ├── .npmrc ├── package.json └── pnpm-lock.yml
如上一節(jié)所述,每個包管理器都會創(chuàng)建鎖定文件。
lock
文件準(zhǔn)確存儲您的項(xiàng)目安裝的每個依賴項(xiàng)的版本從而實(shí)現(xiàn)更可預(yù)測和確定性的安裝。因?yàn)橐蕾嚢姹竞芸赡苁褂冒姹痉秶暶鳎ɡ纾?v1.2.5)所以這個 lock
文件是很重要的,如果您不“l(fā)ock”您的版本,實(shí)際安裝的版本可能會有所不同。
鎖定文件有時也存儲校驗(yàn)和(我記得是一段hash),我們將在安全部分更深入地介紹。
從 npm
v5+ 開始鎖定文件一直是 npm
主要的功能 ( package-lock.json
) ,pnpm
里是 pnpm-lock.yaml
,在 Yarn Berry
中的 yarn.lock
以新的 YAML 格式出現(xiàn)。
在上一節(jié)中,我們看到了傳統(tǒng)方法,將依賴項(xiàng)安裝在 node_modules
文件夾結(jié)構(gòu)中。這是 npm
、Yarn Classic 和 pnpm都使用的方案,(其中 pnpm
比其他方案更有效)。
Yarn Berry
在 PnP 模式下的做法有所不同。依賴項(xiàng)不是 node_modules
文件夾,而是以 zip 文件的形式存儲為 .yarn/cache/
和 .pnp.cjs
文件的組合。
最好將這些鎖定文件置于版本控制之下,因?yàn)槊總€團(tuán)隊(duì)成員都安裝相同的版本,所以它解決了“在你和我的機(jī)器上工作”問題。
下表比較了 npm
、Yarn Classic
、Yarn Berry
和 pnpm
中可用的不同 CLI 命令。這絕不是一個完整的列表,而是一個備忘單。本節(jié)不涉及與workflow 相關(guān)的命令。
npm
和 pnpm
具有許多特別的命令和選項(xiàng)別名,這意味著命令可以有不同的名稱,即$ npm install
與 $ npm add
。 此外,許多命令選項(xiàng)都有縮寫版本,例如 -D
來代替 --save-dev
。
在表格中,我將所有縮寫版本稱為別名。使用這些包管理器,您都可以增加、更新或刪除多個依賴項(xiàng)。
此表涵蓋了用于安裝或更新 package.json
中指定的所有依賴項(xiàng)的依賴項(xiàng)管理命令。
Action | npm | Yarn Classic | Yarn Berry | pnpm |
---|---|---|---|---|
install deps in package.json | npm install alias: i, add | yarn install or yarn | like Classic | pnpm install alias: i |
update deps in package.json acc. semver | npm update alias: up, upgrade | yarn upgrade | yarn semver up (via plugin) | pnpm update alias: up |
update deps in package.json to latest | N/A | yarn upgrade --latest | yarn up | pnpm update --latest alias: -L |
update deps acc. semver | npm update react | yarn upgrade react | yarn semver up react | pnpm up react |
update deps to latest | npm update react@latest | yarn upgrade react --latest | yarn up react | pnpm up -L react |
update deps interactively | N/A | yarn upgrade-interactive | yarn upgrade-interactive (via plugin) | $ pnpm up --interactive alias: -i |
add runtime deps | npm i react | yarn add react | like Classic | pnpm add react |
add dev deps | npm i -D babel alias: --save-dev | yarn add -D babel alias: --dev | like Classic | pnpm add -D babel alias: --save-dev |
add deps to package.json without semver | npm i -E react alias: --save-exact | yarn add -E react alias: --exact | like Classic | pnpm add -E react alias: --save-exact |
uninstall deps and remove from package.json | npm uninstall react alias: remove, rm, r, un, unlink | yarn remove react | like Classic | pnpm remove react alias: rm, un, uninstall |
uninstall deps w/o update of package.json | npm uninstall --no-save | N/A | N/A | N/A |
下面的例子展示了如何在開發(fā)期間管理包。表中使用的術(shù)語:
Package: dependency or binary
Binary: 一種執(zhí)行工具來自
node_modules/.bin/
或者.yarn/cache/
(PnP)
重要的是要理解,Yarn Berry
只允許我們執(zhí)行在 package.json
中或者暴露在 bin/
文件中的指定的二進(jìn)制文件。
Action | npm | Yarn Classic | Yarn Berry | pnpm |
---|---|---|---|---|
install packages globally | npm i -g ntl alias: --global | yarn global add ntl | N/A (global removed) | pnpm add --global ntl |
update packages globally | npm update -g ntl | yarn global upgrade ntl | N/A | pnpm update --global ntl |
remove packages globally | npm uninstall -g ntl | yarn global remove ntl | N/A | pnpm remove --global ntl |
run binaries from terminal | npm exec ntl | yarn ntl | yarn ntl | pnpm ntl |
run binaries from script | ntl | ntl | ntl | ntl |
dynamic package execution | npx ntl | N/A | yarn dlx ntl | pnpm dlx ntl |
add runtime deps | npm i react | yarn add react | like Classic | pnpm add react |
add dev deps | npm i -D babel alias: --save-dev | yarn add -D babel alias: --dev | like Classic | pnpm add -D babel alias: --save-dev |
add deps to package.json without semver | npm i -E react alias: --save-exact | yarn add -E react alias: --exact | like Classic | pnpm add -E react alias: --save-exact |
uninstall deps and remove from package.json | npm uninstall react alias: remove, rm, r, un, unlink | yarn remove react | like Classic | pnpm remove react alias: rm, un, uninstall |
uninstall deps w/o update of package.json | npm uninstall --no-save | N/A | N/A | N/A |
該表涵蓋了一些有用的內(nèi)置命令。如果沒有官方的命令,通??梢酝ㄟ^ npm
包或 Yarn Berry
插件來使用第三方命令。
Action | npm | Yarn Classic | Yarn Berry | pnpm |
---|---|---|---|---|
發(fā)包 | npm publish | yarn publish | yarn npm publish | pnpm publish |
list installed deps | npm ls alias: list, la, ll | yarn list | pnpm list alias: ls | |
list outdated deps | npm outdated | yarn outdated | yarn upgrade-interactive | pnpm outdated |
print info about deps | npm explain ntl alias: why | yarn why ntl | like Classic | pnpm why ntl |
init project | npm init -y npm init (interactive) alias: --yes | yarn init -y yarn init (interactive) alias: --yes | yarn init | pnpm init -y pnpm init (interactive) alias: --yes |
print licenses info | N/A (via third-party package) | yarn licenses list | N/A (or via plugin, other plugin) | N/A (via third-party package) |
update package manager version | N/A (with third-party tools, e.g., nvm) | with npm: yarn policies set-version 1.13.0 | with Corepack: yarn set version 3.1.1 | N/A (with npm, Corepack) |
perform security audit | npm audit | yarn audit | yarn npm audit | pnpm audit |
add deps to package.json without semver | npm i -E react alias: --save-exact | yarn add -E react alias: --exact | like Classic | pnpm add -E react alias: --save-exact |
uninstall deps and remove from package.json | npm uninstall react alias: remove, rm, r, un, unlink | yarn remove react | like Classic | pnpm remove react alias: rm, un, uninstall |
uninstall deps w/o update of package.json | npm uninstall --no-save | N/A | N/A | N/A |
配置包管理器發(fā)生在您的 package.json
和專用的配置文件中。
定義要使用的準(zhǔn)確版本
使用特定的依賴解決策略
配置私有注冊表
告訴包管理器在哪里可以找到 monorepo
中的工作區(qū)
大多數(shù)配置發(fā)生在專用配置文件 .npmrc
中。
如果你想使用 npm
的 workspaces
功能,你必須在 package.json
中添加workspaces 元數(shù)據(jù)字段來告訴 npm 在哪里可以找到子項(xiàng)目或工作空間的文件夾。
// ... "workspaces": [ "hooks", "utils" ] }
每個包管理器都可以使用公共 npm
注冊表。或許你很可能希望重用它們而不將它們發(fā)布到公共注冊表。您可以在 .npmrc
文件中執(zhí)行此操作配置來私有注冊表。( 現(xiàn)在基本都有私有源了)
# .npmrc @doppelmutzi:registry=https://gitlab.doppelmutzi.com/api/v4/projects/41/packages/npm/
npm
存在許多配置選項(xiàng),最好在文檔中查看它們。\
您可以在 package.json
中設(shè)置 yarn
的 workspaces
(必須是私有包)。
{ // ... "private": true, "workspaces": ["workspace-a", "workspace-b"] }
任何可選配置都進(jìn)入一個 .yarnrc
文件。一個常見的配置選項(xiàng)是設(shè)置一個 yarn-path:
它強(qiáng)制每個團(tuán)隊(duì)成員使用指定的二進(jìn)制版本。yarn-path
指向包含特定 Yarn
版本的文件夾(例如 .yarn/releases/
)。您可以使用命令來安裝統(tǒng)一的 Yarn Classic
版本(classic.yarnpkg.com/en/docs/cli…)。
在 Yarn Berry
中配置 workspaces
和在 Yarn Classic
中的配置方式類似(package.json
)。 大多數(shù) Yarn Berry
配置發(fā)生在 .yarnrc.yml
中,并且有許多可用的配置選項(xiàng)。
# .yarnrc.yml yarnPath: .yarn/releases/yarn-3.1.1.cjs
yarn berry
可以用 $> yarn plugin import <name>
這種導(dǎo)入方式來擴(kuò)展插件(yarnpkg.com/cli/plugin/…),這個命令也會更新 .yarnrc.yml
。
# .yarnrc.yml plugins: - path: .yarn/plugins/@yarnpkg/plugin-semver-up.cjs spec: "https://raw.githubusercontent.com/tophat/yarn-plugin-semver-up/master/bundles/%40yarnpkg/plugin-semver-up.js"
如歷史部分所述,因?yàn)榧嫒菪缘年P(guān)系,PnP 嚴(yán)格模式下的依賴關(guān)系可能存在某些問題。此類 PnP 問題有一個典型的解決方案:包擴(kuò)展配置策略。
# .yarnrc.yml packageExtensions: "styled-components@*": dependencies: react-is: "*"
pnpm
使用與 npm
相同的配置機(jī)制,因此您可以使用 .npmrc
文件。配置私有注冊表的工作方式也與使用 npm
相同。借助 pnpm 的工作空間功能可以支持多包項(xiàng)目。要初始化 monorepo
,您必須在 pnpm-workspace.yaml
文件中指定包的位置。
# pnpm-workspace.yaml packages: - 'packages/**'
(這里其實(shí)就是三種概念,單倉庫多項(xiàng)目,單倉庫單項(xiàng)目,多倉庫多項(xiàng)目)
monorepo
是一個包含多個項(xiàng)目的存儲庫,這些項(xiàng)目被稱為 workspace
或者包。將所有內(nèi)容保存在一個地方而不是使用多個存儲庫是一種項(xiàng)目組織策略。
當(dāng)然,這會帶來額外的復(fù)雜性。Yarn Classic
是第一個啟用此功能的,但現(xiàn)在每個主要的包管理器都提供了工作區(qū)功能。本節(jié)展示如何使用每個不同的包管理器配置工作區(qū)。
npm
團(tuán)隊(duì)在 v7 中發(fā)布了期待已久的npm 工作區(qū)功能。它包含許多 CLI 命令,可幫助從根包中管理多包項(xiàng)目。大多數(shù)命令可以與 workspace
相關(guān)的選項(xiàng)一起使用以告訴 npm
它是否應(yīng)該針對特定、多個或所有工作空間運(yùn)行。
# Installing all dependencies for all workspaces $ npm i --workspaces. # run against one package $ npm run test --workspace=hooks # run against multiple packages $ npm run test --workspace=hooks --workspace=utils # run against all $ npm run test --workspaces # ignore all packages missing test $ npm run test --workspaces --if-present
tips: 與其他包管理器相比,npm
v8 目前不支持高級過濾或并行執(zhí)行多個與工作區(qū)相關(guān)的命令。
2017 年 8 月,Yarn
團(tuán)隊(duì)宣布在workspace功能方面提供 monorepo
支持。在此之前,只能在Lerna等第三方軟件的多包項(xiàng)目中使用包管理器。Yarn
的這一新增功能也為其他包管理器實(shí)現(xiàn)此類功能鋪平了道路。
如果你有興趣,可以參考如何在有和沒有 Lerna 的情況下使用 Yarn Classic 的工作區(qū)功能。但是這篇文章只會介紹一些必要的命令,以幫助您管理 Yarn Classic
工作區(qū)設(shè)置中的依賴關(guān)系。
# 為所有工作空間安裝所有依賴項(xiàng) $ yarn # 顯示依賴關(guān)系樹 $ yarn workspaces info # 再一個包運(yùn)行啟動 $ yarn workspace awesome - package start # 將Webpack添加到包 $ yarn workspace awesome - package add - D webpack # add React 對所有包 $ yarn add react -W
Yarn Berry
從一開始就以工作區(qū)為特色,因?yàn)樗膶?shí)現(xiàn)是建立在 Yarn Classic
的概念之上的。在Reddit 評論中,Yarn Berry 的主要開發(fā)人員簡要概述了面向工作空間的功能,包括:
$ yarn add --interactive: 可以在安裝包時重用來自其他工作區(qū)的版本
$ yarn up:更新所有工作區(qū)的包
$ yarn workspaces focus:僅為單個工作區(qū)安裝依賴項(xiàng)
$ yarn workspaces foreach:在所有工作區(qū)上運(yùn)行命令
Yarn Berry
使用大量可用于 package.json
文件的 dependencies
或 devDependencies
字段的協(xié)議。其中就有 workspace
協(xié)議。
與 Yarn Classic
的工作區(qū)相比,Yarn Berry
明確定義依賴項(xiàng)必須是此 monorepo
中的包之一。否則如果版本不匹配,Yarn Berry
可能會嘗試從遠(yuǎn)程注冊表獲取其版本。
{ // ... "dependencies": { "@doppelmutzi/hooks": "workspace:*", "http-server": "14.0.0", // ... } }
通過 workspace
這種協(xié)議,pnpm
促成了類似于 Yarn Berry
的 monorepo
項(xiàng)目。許多 pnpm
命令接受 --recursive (-r)
或者 --filter 這種在 monorepo
上下文中特別有用的選項(xiàng)。它的原生過濾命令也是對 Lerna
的一個很好的補(bǔ)充。
# prune all workspaces pnpm -r exec -- rm -rf node_modules && rm pnpm-lock.yaml # run all tests for all workspaces with scope @doppelmutzi pnpm recursive run test --filter @doppelmutzi/`
性能是選型決策的關(guān)鍵部分。本節(jié)展示了基于一個小型和一個中型項(xiàng)目的基準(zhǔn)測試。以下是有關(guān)示例項(xiàng)目的一些說明:
兩組基準(zhǔn)都不使用工作區(qū)功能
小項(xiàng)目指定33個依賴
中項(xiàng)目指定44個依賴
我用三個用例 (UC) 對我們的每個包管理器變體進(jìn)行了一次測量。要了解詳細(xì)的評估和解釋,請查看項(xiàng)目 1 (P1)和項(xiàng)目 2 (P2)的結(jié)果。
UC 1:沒有緩存/存儲,沒有鎖定文件,沒有 node_modules
或 .pnp.cjs
UC 2:存在緩存/存儲,沒有鎖定文件,沒有 node_modules
或 .pnp.cjs
UC 3:存在緩存/存儲,存在鎖定文件,沒有 node_modules
或 .pnp.cjs
我使用工具gnomon來測量安裝消耗的時間( yarn
| gnomon
)。此外我測量了生成文件的大小 $ du -sh node_modules
。
Performance results for Project 1 | |||||||
---|---|---|---|---|---|---|---|
Method | npm v8.1.2 | Yarn Classic v1.23.0 | pnpm v6.24.4 | Yarn Berry PnP loose v3.1.1 | Yarn Berry PnP strict v3.1.1 | Yarn Berry node_modules v3.1.1 | Yarn Berry pnpm v3.1.1 |
UC 1 | 86.63s | 108.89s | 43.58s | 31.77s | 30.13s | 56.64s | 60.91s |
UC 2 | 41.54s | 65.49s | 26.43s | 12.46s | 12.66s | 46.36s | 40.74s |
UC 3 | 23.59s | 40.35s | 20.32s | 1.61s | 1.36s | 28.72s | 31.89s |
Files and size | package-lock.json: 1.3M node_modules: 467M | node_modules: 397M yarn.lock: 504K | pnpm-lock.yaml: 412K node_modules: 319M | yarn.lock: 540K cache: 68M unplugged: 29M .pnp.cjs: 1.6M | yarn.lock: 540K cache: 68M unplugged: 29M .pnp.cjs: 1.5M | node_modules: 395M yarn.lock: 540K cache: 68M | node_modules: 374M yarn.lock: 540K cache: 68M |
Performance results for Project 2 | |||||||
---|---|---|---|---|---|---|---|
Method | npm v8.1.2 | Yarn Classic v1.23.0 | pnpm v6.24.4 | Yarn Berry PnP loose v3.1.1 | Yarn Berry PnP strict v3.1.1 | Yarn Berry node_modules v3.1.1 | Yarn Berry pnpm v3.1.1 |
UC 1 | 34.91s | 43.26s | 15.6s | 13.92s | 6.44s | 23.62s | 20.09s |
UC 2 | 7.92s | 33.65s | 8.86s | 7.09s | 5.63s | 15.12s | 14.93s |
UC 3 | 5.09s | 15.64s | 4.73s | 0.93s | 0.79s | 8.18s | 6.02s |
Files and size | package-lock.json: 684K node_modules: 151M | yarn.lock: 268K node_modules: 159M | pnpm-lock.yaml: 212K node_modules: 141M | .pnp.cjs: 1.1M .pnp.loader.mjs: 8.0K yarn.lock: 292K .yarn: 38M | .pnp.cjs: 1.0M .pnp.loader.mjs: 8.0K yarn.lock: 292K .yarn: 38M | yarn.lock: 292K node_modules: 164M cache: 34M | yarn.lock: 292K node_modules: 156M cache: 34M |
npm
在處理壞包時有點(diǎn)過于寬容并且遇到了一些直接影響許多項(xiàng)目的安全漏洞。例如,在 5.7.0 版本中,當(dāng)您在 Linux 操作系統(tǒng)上執(zhí)行 sudo npm
命令時,可以更改系統(tǒng)文件的所有權(quán),從而導(dǎo)致操作系統(tǒng)無法使用。
另一起事件發(fā)生在 2018 年,涉及比特幣被盜。 Node.js 包EventStream在其 3.3.6 版本中添加了惡意依賴項(xiàng)。這個惡意包包含一個加密方法試圖從開發(fā)者的機(jī)器上竊取比特幣。
為了幫助解決這些問題,新的 npm
版本使用密碼算法來檢查您安裝的軟件包的完整性。SHA-512。
Yarn Classic
和 Yarn Berry
從一開始就使用校驗(yàn)和來檢驗(yàn)每一個包的完整性。Yarn
還試圖阻止您檢索在 package.json
中未聲明的惡意包:如果發(fā)現(xiàn)不匹配,則中止安裝。
PnP 模式下的 Yarn Berry
沒有傳統(tǒng) node_modules
方式的安全問題。與 Yarn Classic
相比,Yarn Berry
提高了命令執(zhí)行的安全性。您只能執(zhí)行已在 package.json
聲明的包。此安全功能類似于 pnpm
,我將在下面進(jìn)行描述。
pnpm
還是使用校驗(yàn)和來驗(yàn)證每個已安裝包的完整性,然后再執(zhí)行其代碼。
正如我們在上面提到的,npm
和 Yarn Classic
都存在由于提升而導(dǎo)致的安全問題。pnpm
避免了這種情況,因?yàn)樗墓芾砟P筒皇褂锰嵘?;相反,它會生成嵌?node_modules
文件夾,從而消除非法依賴訪問的風(fēng)險(xiǎn)。這意味著依賴關(guān)系都在 .package.json
中聲明了。
正如我們所討論的,這在 monorepo
設(shè)置中尤其重要,因?yàn)樘嵘惴ㄓ袝r會導(dǎo)致依賴的不確定性。
感謝各位的閱讀,以上就是“JavaScript包管理器實(shí)例比較分析”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對JavaScript包管理器實(shí)例比較分析這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!
網(wǎng)頁題目:JavaScript包管理器實(shí)例比較分析
當(dāng)前URL:http://muchs.cn/article10/ghipdo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開發(fā)、企業(yè)建站、網(wǎng)站改版、網(wǎng)站收錄、網(wǎng)頁設(shè)計(jì)公司、外貿(mào)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)