包管理器領域的三個主要參與者:
實際上我們已經在所有包管理器中實現了基本相似的功能,因此您很可能會根據非功能性要求來決定使用哪個包管理器,例如安裝速度、儲存消耗或實際情況。
當然,您選擇使用每個包管理器的方式會有所不同,但它們都有基本一致的概念。以上這些包管理器都可以執行以下指令:
然而儘管如此,包管理器在底層還是有所不同的。傳統上 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 [email protected] --activate
您可以將 pnpm
作為 npm
包來安裝: $ npm i -g pnpm
。您還可以使用 Corepack 安裝 pnpm :
$ corepack prepare [email protected] --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 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/`
效能是選型決策的關鍵部分。本節展示了基於一個小型和一箇中型專案的基準測試。以下是有關範例專案的一些說明:
我用三個用例 (UC) 對我們的每個包管理器變體進行了一次測量。要了解詳細的評估和解釋,請檢視專案 1 (P1)和專案 2 (P2)的結果。
node_modules
或 .pnp.cjs
node_modules
或 .pnp.cjs
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
設定中尤其重要,因為提升演演算法有時會導致依賴的不確定性。
npm | Yarn Classic | Yarn Berry | pnpm |
Svelte | React | Jest (with node_modules) | Vue 3 |
Preact | Angular | Storybook (with node_modules) | Browserlist |
Express.js | Ember | Babel (with node_modules) | Prisma |
Meteor | Next.js | Redux Toolkit (with node_modules) | SvelteKit |
Apollo Server | Gatsby | ||
Nuxt | |||
Create React App | |||
webpack-cli | |||
Emotion |
不同的包管理器原理確實存在很大的差異。
pnpm
起初看起來像 npm
,因為它們的 CLI 用法相似,但管理依賴項卻大不相同;pnpm
的方法帶來更好的效能和最佳的磁碟空間效率。Yarn Classic
仍然很受歡迎,但它被認為是遺留軟體,並且在不久的將來可能會放棄支援。Yarn Berry PnP
是全新的,但人們尚未意識到其再次徹底改變包管理器領域的潛力。
多年來,許多使用者詢問誰使用哪些包管理器,總體而言人們似乎對 Yarn Berry PnP
的成熟度和採用特別感興趣。
本文的目的是為您提供多種觀點,以決定您自己使用哪個包管理器。我想指出,我不推薦特定的包管理器。這取決於你如何衡量不同的要求——所以你仍然可以選擇你喜歡的任何東西!
英文原文地址:https://blog.logrocket.com/javascript-package-managers-compared/
更多node相關知識,請存取:!
以上就是JavaScript包管理器比較:Npm vs Yarn vs Pnpm的詳細內容,更多請關注TW511.COM其它相關文章!