您好,登錄后才能下訂單哦!
這篇文章主要講解了“JavaScript包管理器實例比較分析”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“JavaScript包管理器實例比較分析”吧!
包管理器領域的三個主要參與者:
npm
Yarn
高性能 npm (pnpm)
實際上我們已經在所有包管理器中實現了基本相似的功能,因此您很可能會根據非功能性要求來決定使用哪個包管理器,例如安裝速度、存儲消耗或實際情況。
當然,您選擇使用每個包管理器的方式會有所不同,但它們都有基本一致的概念。以上這些包管理器都可以執行以下指令:
讀寫數據
批量安裝或更新所有依賴項
添加、更新和刪除依賴項
運行腳本
發布包
然而盡管如此,包管理器在底層還是有所不同的。傳統上 npm
和 Yarn
將依賴項安裝在一個平鋪的node_modules文件夾中。(這里注意先后順序,是 yarn
先平鋪的,之前 npm
是遞歸)。但是平鋪也會造成一系列的安全問題。
依賴結構的不確定性。
扁平化算法本身的復雜性很高,耗時較長。
項目中仍然可以非法訪問
有聲明過依賴的包
因此,pnpm
在 node_modules
文件夾中引入了一些新概念來更高效的存儲依賴,。Yarn Berry
甚至通過完全放棄 node_modules
的 (PnP) 模式(另一個文章會具體說明)來走得更遠。
最早發布的包管理器是 npm
,早在 2010 年 1 月。它就確立了今天包管理器工作的核心原則。但是既然 npm
已經存在 10 多年了,為什么還有其他選擇?以下是出現這種情況的一些關鍵原因:
node_modules
文件夾結構的依賴關系解析算法不同(嵌套 & 平鋪、node_modules
vs. PnP mode)
依賴提升方式不同(hoisting
)
locking
格式不同(性能都不同,比如 yarn
自己寫的那一套)
磁盤存儲包文件方式不同(空間效率不同)
多包項目(又名 workspaces
)的支持不同,這會影響 monorepos
的可維護性和速度
新工具和命令的需求不同(通過插件和社區工具對可擴展性的需求不同)
可配置性和靈活性不同
讓我們深入了解一下 npm
崛起后這些方面如何確定的歷史,Yarn Classic
如何解決其中的一些問題,pnpm
如何擴展這些概念,以及 Yarn Berry
作為 Yarn Classic
的繼任者如何打破這些傳統的概念和流程。
npm
是包管理器的鼻祖。許多人錯誤地認為 npm
是“Node package manager”的首字母縮寫詞,但事實并非如此。
它的發布構成了一場革命,因為在此之前,項目依賴項都是手動下載和管理的。npm
引入了諸如文件及其元數據字段、將依賴項存儲在node_modules
, 自定義腳本, 公共和私有包等等。
2020 年,GitHub 收購了 npm,所以原則上 npm
現在歸微軟管理。在撰寫本文時,最新的主要版本是 v8,于 2021 年 10 月發布。
在 2016 年 10 月,Facebook 宣布與 Google 和其他一些公司合作開發一個新的包管理器(engineering.fb.com/2016/10/11/…),以解決 npm 當時存在的一致性、安全性和性能問題。他們將替代品命名為Yarn。
盡管 Yarn
還是基于 npm
的許多概念和流程來架構設計的,但 Yarn
還是對包管理器領域產生了重大影響。與 npm
相比,Yarn
并行化操作以加快安裝過程,這一直是 npm
早期版本的主要痛點。
Yarn
為讀寫、安全性和性能設定了更高的標準,還發明了許多概念(后來npm
也為此做了很多改進),包括:
monorepo
支持
緩存安裝
離線下載
文件鎖(Locking
)
Yarn v1 于 2020 年進入維護模式 。從那時起,v1.x 系列被認為是舊版,并更名為 Yarn Classic
。它的繼任者 Yarn v2 (Berry) 現在是更加活躍的開發分支。
pnpm
pnpm
的第 1 版由 Zoltan Kochan于 2017 年發布。它是 npm
的替代品,所以如果你有一個 npm
項目,你可以馬上使用 pnpm
!
創建 pnpm
的主要原因是 npm
和 Yarn
對于跨項目使用的依賴項存儲結構非常冗余。盡管 Yarn Classic
比 npm
具有速度優勢,但它使用相同的依賴解析方法,這對 pnpm
來說是不行的:npm
和 Yarn Classic
使用 hoisting
來平鋪他們的 node_modules
.
pnpm
沒有優化之前的結構,而是引入了另一種依賴解決策略:內容尋址的一種存儲結構。此方法生成的 node_modules
文件夾其實是依賴于全局存儲在主文件夾上的 ~/.pnpm-store/
目錄。每個版本的依賴項都物理形式存儲在該目錄文件夾中一次,構成單一的源地址來節省相當多的磁盤空間。
node_modules
結構是通過使用 symlinks
創建依賴關系的嵌套結構(其中文件夾內每個文件/包都是通過硬鏈接存儲)官方文檔中的下圖闡明了這一點。(待填坑:軟硬鏈接)
2021 年報告中可見 pnpm
的影響力:因為他們在內容可尋址存儲方面的創新,競爭對手都希望采用 pnpm
的概念,比如象征性鏈接的結構和包的高效磁盤管理。
Yarn 2于 2020 年 1 月發布,被宣傳為原始 Yarn
的重大升級。Yarn
團隊將其稱為 Yarn Berry
以更明顯地表明它本質上是一個具有新的代碼庫和新的原則規范的新包管理器。
Yarn Berry
的主要創新是其即插即用 (PnP)方法,它是作為修復node_modules的策略。不是生成node_modules
的策略,而是生成一個帶有依賴查找表的文件 .pnp.cjs
,因為它是單個文件而不是嵌套的文件夾結構,所以可以更有效地處理依賴。此外,每個包都以zip 文件的形式存儲在文件夾內來替代 .yarn/cache/
,占用的磁盤空間也比 node_modules
少。
所有這些變化如此之快以至于在發布后引起了很大的爭議。PnP 這種破壞性的重大更改要求維護者更新他們現有的包以便與其兼容。默認情況下使用全新的 PnP 方法并且恢復到 node_modules
最初并不簡單,這導致許多知名開發人員沒有加入其中的考慮且公開批評 Yarn 2。
此后,Yarn Berry
團隊在其后續版本中解決了許多問題。為了解決 PnP 的不兼容問題,團隊提供了方法來輕松更改默認操作模式。在node_modules插件的幫助下,切換回傳統 node_modules
方法只需要一行配置。
此外,隨著時間的推移,JavaScript 生態系統為 PnP 提供了越來越多的支持,正如您在此兼容性表中所見,一些大型項目已經開始采用 Yarn Berry
。
盡管 Yarn Berry
還很年輕,但它也已經對包管理器領域產生了影響——pnpm
在 2020 年末采用了PnP 方法。
首先必須在每個開發人員的本地和 CI/CD 系統上安裝包管理器。
npm
與 Node.js
一起提供,因此不需要額外的步驟。除了為您的操作系統下載Node.js 安裝程序外,使用 CLI 工具管理軟件版本已成為一種常見做法。在 Node 的上下文中,Node Version Manager (nvm) 或 Volta 已成為非常方便的實用程序。
您可以通過不同的方式安裝 Yarn 1,例如,作為 npm
包來安裝:.$ npm i -g yarn
要從Yarn Classic 遷移到 Yarn Berry,推薦的方法是:
安裝或更新 Yarn Classic
到最新的版本
使用命令升級到最新的現代版本
yarn set version berry
但是,在此推薦的安裝 Yarn Berry方法是通過 Corepack。
Corepack是由 Yarn Berry 的開發者創建的。該計劃最初被命名為包管理器管理器(pmm) ?,并在 LTS v16 中與 Node 合并。
在 Corepack 的幫助下,因為 Node 包含 Yarn Classic
、Yarn Berry
和 pnpm
二進制文件所以您不必“單獨”安裝的 npm
的替代包管理器。這些墊片允許用戶運行 Yarn 和 pnpm 命令而無需先顯式安裝它們,也不會弄亂 Node 發行版。
Corepack 預裝了 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
在本節中,您將一目了然地看到不同包管理器的主要特征。您可以輕松發現配置特定包管理器涉及哪些文件,以及哪些文件是由安裝步驟生成的。
所有包管理器都將所有重要的元信息存儲在項目清單package.json文件中。 此外,根級別的配置文件可以被用來設置不同的私有包或者不同的依賴項解析配置。
在安裝步驟中,依賴項 dependencies
被存儲在文件結構中,例如 node_modules
并生成鎖定文件 locking
。本節不考慮工作區設置,因此所有示例僅顯示存儲依賴項的單個位置。
使用$ npm install
或較短的 $ npm i
會生成一個 package-lock.json
文件和一個 node_modules
文件夾。還有 .npmrc
這種可配置的文件可以放在根級別目錄里面。有關 locking
文件的更多信息,請參閱下一節。
. ├── node_modules/ ├── .npmrc ├── package-lock.json └── package.json
運行 $ yarn
會創建一個 yarn.lock
文件和一個 node_modules
文件夾。.yarnrc
文件也可以是配置的選項,Yarn Classic
也支持 .npmrc
文件。或者可以使用緩存文件夾 .yarn/cache/
和本地存儲的最近的 Yarn Classic
版本 .yarn/releases/
。
. ├── .yarn/ │ ├── cache/ │ └── releases/ │ └── yarn-1.22.17.cjs ├── node_modules/ ├── .yarnrc ├── package.json └── yarn.lock
因為這種特殊的安裝模式,比使用其他包管理器您必須在 Yarn Berry
項目中處理更多的文件和文件夾。有些是可選的,有些是強制性的。
Yarn Berry
不再支持 .npmrc
或者 .yarnrc
;他需要一個 .yarnrc.yml。對于傳統的生成 node_modules
文件夾的工作流程,您必須提供 nodeLinker
配置來使用 node_modules
或者 pnpm
的配置(這塊沒看懂)。
# .yarnrc.yml nodeLinker: node-modules # or pnpm
運行 $ yarn
會將所有依賴項安裝在一個 node_modules
文件夾中。并且生成一個 yarn.lock
文件,該文件較新但與 Yarn Classic
不兼容。此外,還會生成一個用于離線安裝的 .yarn/cache/
文件夾。該文件夾是可選的,用于存儲項目使用的 Yarn Berry
版本。
. ├── .yarn/ │ ├── cache/ │ └── releases/ │ └── yarn-3.1.1.cjs ├── node_modules/ ├── .yarnrc.yml ├── package.json └── yarn.lock
無論是對于PnP 的嚴格模式還是松散模式,跟著 .pnp.cjs
和 yarn.lock
來執行 $ yarn
都會生成一個 .yarn/cache/
還有 .yarn/unplugged
。PnP strict 是默認模式,如果想要配置 loose 模式,需要如下形式開啟??:
# .yarnrc.yml nodeLinker: pnp pnpMode: loose
在 PnP 項目中,除了 releases
文件夾之外,.yarn
文件夾很可能還包含一個提供IDE 支持的 sdk/
文件夾。根據您的用例,.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
項目的初始狀態一樣,pnpm
也需要 package.json
文件。使用 $ pnpm i
安裝依賴項后,會生成一個 node_modules
文件夾,但由于其內容是可尋址存儲方式,其結構完全不同。
pnpm
還會生成自己的鎖定文件 pnp-lock.yml
。 您可以使用可選文件 .npmrc
提供附加配置。
. ├── node_modules/ │ └── .pnpm/ ├── .npmrc ├── package.json └── pnpm-lock.yml
如上一節所述,每個包管理器都會創建鎖定文件。
lock
文件準確存儲您的項目安裝的每個依賴項的版本從而實現更可預測和確定性的安裝。因為依賴版本很可能使用版本范圍聲明(例如,≥ v1.2.5)所以這個 lock
文件是很重要的,如果您不“lock”您的版本,實際安裝的版本可能會有所不同。
鎖定文件有時也存儲校驗和(我記得是一段hash),我們將在安全部分更深入地介紹。
從 npm
v5+ 開始鎖定文件一直是 npm
主要的功能 ( package-lock.json
) ,pnpm
里是 pnpm-lock.yaml
,在 Yarn Berry
中的 yarn.lock
以新的 YAML 格式出現。
在上一節中,我們看到了傳統方法,將依賴項安裝在 node_modules
文件夾結構中。這是 npm
、Yarn Classic 和 pnpm都使用的方案,(其中 pnpm
比其他方案更有效)。
Yarn Berry
在 PnP 模式下的做法有所不同。依賴項不是 node_modules
文件夾,而是以 zip 文件的形式存儲為 .yarn/cache/
和 .pnp.cjs
文件的組合。
最好將這些鎖定文件置于版本控制之下,因為每個團隊成員都安裝相同的版本,所以它解決了“在你和我的機器上工作”問題。
下表比較了 npm
、Yarn Classic
、Yarn Berry
和 pnpm
中可用的不同 CLI 命令。這絕不是一個完整的列表,而是一個備忘單。本節不涉及與workflow 相關的命令。
npm
和 pnpm
具有許多特別的命令和選項別名,這意味著命令可以有不同的名稱,即$ npm install
與 $ npm add
。 此外,許多命令選項都有縮寫版本,例如 -D
來代替 --save-dev
。
在表格中,我將所有縮寫版本稱為別名。使用這些包管理器,您都可以增加、更新或刪除多個依賴項。
此表涵蓋了用于安裝或更新 package.json
中指定的所有依賴項的依賴項管理命令。
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 |
下面的例子展示了如何在開發期間管理包。表中使用的術語:
Package: dependency or binary
Binary: 一種執行工具來自
node_modules/.bin/
或者.yarn/cache/
(PnP)
重要的是要理解,Yarn Berry
只允許我們執行在 package.json
中或者暴露在 bin/
文件中的指定的二進制文件。
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 |
該表涵蓋了一些有用的內置命令。如果沒有官方的命令,通常可以通過 npm
包或 Yarn Berry
插件來使用第三方命令。
Action | npm | Yarn Classic | Yarn Berry | pnpm |
---|---|---|---|---|
發包 | 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 |
配置包管理器發生在您的 package.json
和專用的配置文件中。
定義要使用的準確版本
使用特定的依賴解決策略
配置私有注冊表
告訴包管理器在哪里可以找到 monorepo
中的工作區
大多數配置發生在專用配置文件 .npmrc
中。
如果你想使用 npm
的 workspaces
功能,你必須在 package.json
中添加workspaces 元數據字段來告訴 npm 在哪里可以找到子項目或工作空間的文件夾。
// ... "workspaces": [ "hooks", "utils" ] }
每個包管理器都可以使用公共 npm
注冊表。或許你很可能希望重用它們而不將它們發布到公共注冊表。您可以在 .npmrc
文件中執行此操作配置來私有注冊表。( 現在基本都有私有源了)
# .npmrc @doppelmutzi:registry=https://gitlab.doppelmutzi.com/api/v4/projects/41/packages/npm/
npm
存在許多配置選項,最好在文檔中查看它們。\
您可以在 package.json
中設置 yarn
的 workspaces
(必須是私有包)。
{ // ... "private": true, "workspaces": ["workspace-a", "workspace-b"] }
任何可選配置都進入一個 .yarnrc
文件。一個常見的配置選項是設置一個 yarn-path:
它強制每個團隊成員使用指定的二進制版本。yarn-path
指向包含特定 Yarn
版本的文件夾(例如 .yarn/releases/
)。您可以使用命令來安裝統一的 Yarn Classic
版本(classic.yarnpkg.com/en/docs/cli…)。
在 Yarn Berry
中配置 workspaces
和在 Yarn Classic
中的配置方式類似(package.json
)。 大多數 Yarn Berry
配置發生在 .yarnrc.yml
中,并且有許多可用的配置選項。
# .yarnrc.yml yarnPath: .yarn/releases/yarn-3.1.1.cjs
yarn berry
可以用 $> yarn plugin import <name>
這種導入方式來擴展插件(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"
如歷史部分所述,因為兼容性的關系,PnP 嚴格模式下的依賴關系可能存在某些問題。此類 PnP 問題有一個典型的解決方案:包擴展配置策略。
# .yarnrc.yml packageExtensions: "styled-components@*": dependencies: react-is: "*"
pnpm
使用與 npm
相同的配置機制,因此您可以使用 .npmrc
文件。配置私有注冊表的工作方式也與使用 npm
相同。借助 pnpm 的工作空間功能可以支持多包項目。要初始化 monorepo
,您必須在 pnpm-workspace.yaml
文件中指定包的位置。
# pnpm-workspace.yaml packages: - 'packages/**'
(這里其實就是三種概念,單倉庫多項目,單倉庫單項目,多倉庫多項目)
monorepo
是一個包含多個項目的存儲庫,這些項目被稱為 workspace
或者包。將所有內容保存在一個地方而不是使用多個存儲庫是一種項目組織策略。
當然,這會帶來額外的復雜性。Yarn Classic
是第一個啟用此功能的,但現在每個主要的包管理器都提供了工作區功能。本節展示如何使用每個不同的包管理器配置工作區。
npm
團隊在 v7 中發布了期待已久的npm 工作區功能。它包含許多 CLI 命令,可幫助從根包中管理多包項目。大多數命令可以與 workspace
相關的選項一起使用以告訴 npm
它是否應該針對特定、多個或所有工作空間運行。
# 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 目前不支持高級過濾或并行執行多個與工作區相關的命令。
2017 年 8 月,Yarn
團隊宣布在workspace功能方面提供 monorepo
支持。在此之前,只能在Lerna等第三方軟件的多包項目中使用包管理器。Yarn
的這一新增功能也為其他包管理器實現此類功能鋪平了道路。
如果你有興趣,可以參考如何在有和沒有 Lerna 的情況下使用 Yarn Classic 的工作區功能。但是這篇文章只會介紹一些必要的命令,以幫助您管理 Yarn Classic
工作區設置中的依賴關系。
# 為所有工作空間安裝所有依賴項 $ yarn # 顯示依賴關系樹 $ yarn workspaces info # 再一個包運行啟動 $ yarn workspace awesome - package start # 將Webpack添加到包 $ yarn workspace awesome - package add - D webpack # add React 對所有包 $ yarn add react -W
Yarn Berry
從一開始就以工作區為特色,因為它的實現是建立在 Yarn Classic
的概念之上的。在Reddit 評論中,Yarn Berry 的主要開發人員簡要概述了面向工作空間的功能,包括:
$ yarn add --interactive: 可以在安裝包時重用來自其他工作區的版本
$ yarn up:更新所有工作區的包
$ yarn workspaces focus:僅為單個工作區安裝依賴項
$ yarn workspaces foreach:在所有工作區上運行命令
Yarn Berry
使用大量可用于 package.json
文件的 dependencies
或 devDependencies
字段的協議。其中就有 workspace
協議。
與 Yarn Classic
的工作區相比,Yarn Berry
明確定義依賴項必須是此 monorepo
中的包之一。否則如果版本不匹配,Yarn Berry
可能會嘗試從遠程注冊表獲取其版本。
{ // ... "dependencies": { "@doppelmutzi/hooks": "workspace:*", "http-server": "14.0.0", // ... } }
通過 workspace
這種協議,pnpm
促成了類似于 Yarn Berry
的 monorepo
項目。許多 pnpm
命令接受 --recursive (-r)
或者 --filter 這種在 monorepo
上下文中特別有用的選項。它的原生過濾命令也是對 Lerna
的一個很好的補充。
# 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/`
性能是選型決策的關鍵部分。本節展示了基于一個小型和一個中型項目的基準測試。以下是有關示例項目的一些說明:
兩組基準都不使用工作區功能
小項目指定33個依賴
中項目指定44個依賴
我用三個用例 (UC) 對我們的每個包管理器變體進行了一次測量。要了解詳細的評估和解釋,請查看項目 1 (P1)和項目 2 (P2)的結果。
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
在處理壞包時有點過于寬容并且遇到了一些直接影響許多項目的安全漏洞。例如,在 5.7.0 版本中,當您在 Linux 操作系統上執行 sudo npm
命令時,可以更改系統文件的所有權,從而導致操作系統無法使用。
另一起事件發生在 2018 年,涉及比特幣被盜。 Node.js 包EventStream在其 3.3.6 版本中添加了惡意依賴項。這個惡意包包含一個加密方法試圖從開發者的機器上竊取比特幣。
為了幫助解決這些問題,新的 npm
版本使用密碼算法來檢查您安裝的軟件包的完整性。SHA-512。
Yarn Classic
和 Yarn Berry
從一開始就使用校驗和來檢驗每一個包的完整性。Yarn
還試圖阻止您檢索在 package.json
中未聲明的惡意包:如果發現不匹配,則中止安裝。
PnP 模式下的 Yarn Berry
沒有傳統 node_modules
方式的安全問題。與 Yarn Classic
相比,Yarn Berry
提高了命令執行的安全性。您只能執行已在 package.json
聲明的包。此安全功能類似于 pnpm
,我將在下面進行描述。
pnpm
還是使用校驗和來驗證每個已安裝包的完整性,然后再執行其代碼。
正如我們在上面提到的,npm
和 Yarn Classic
都存在由于提升而導致的安全問題。pnpm
避免了這種情況,因為它的管理模型不使用提升;相反,它會生成嵌套 node_modules
文件夾,從而消除非法依賴訪問的風險。這意味著依賴關系都在 .package.json
中聲明了。
正如我們所討論的,這在 monorepo
設置中尤其重要,因為提升算法有時會導致依賴的不確定性。
感謝各位的閱讀,以上就是“JavaScript包管理器實例比較分析”的內容了,經過本文的學習后,相信大家對JavaScript包管理器實例比較分析這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。