
套件管理器領域的三個主要參與者:
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) 現在是更活躍的開發分支。
pnpmpnpm的第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 install update update deps, package.json acc. semverbver | parndeemveralt | up | 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 | depsup | . semver parn accup | . 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 upgrapm | up -L react update deps interactively N/A yarn upgrapm up -L reactupdate | depsinter --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, unll unll pate | |
| /ll unp 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 globdob | update | -gdate n | wtl mtl來自 | |
| | | | | |
| | | | | |
| | | | | |
| 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: unlink unll pemove react like Classic pnpm |
| remove 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 | pn deps | npm explain ntl|
| alias: why yarn | why | -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) | yarnlicenses list | N/ A (or via plugin, other plugin) | N/A (via third-party package) | |
| update package manager version | N/A (with third-party tools, eg, nvm) | with npm: yarn policies set-version 1.13.0 | with Core nvm : yarn set version 3.1.1 | N/A (with npm, Corepack) | |
| perform security audit | npm audit | yarn audit | yarn npm audit | pn reactit | |
| add deps to package.json without semver | npm i -pn reactalias: --Edave y | -- -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)的結果。
.pnp.cjs node_modulesnode_modules或.pnp.cjs UC 2: .pnp.cjsnode_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 pn v3.1.1Yarn Berry node_modules v3.1.1 | Yarn Berry pn v3.1.1 Yarn Berry node_modules v3.1.1 Yarn Berry pn v3.1.1 pm node_modules v3.1.1 Yarn Berry |
| pn | v3.1.1 | pm | 3189631313191313 | . | 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.596s 40.35.
| 9s | 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 unpled: 29M ugg.p. 9M . 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 | pn v3.1.1 Yarn Berry node_modules v3.1.1 Yarn Berry pn v3.1.1 Yarn Berry node_modules v3.1.1Yarn |
| Berry | pn | v3.1.1 | 9.511699.113 | . | 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.73 | ) | s | . |
| 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: 1.1M | .pnp.loader.mjs: M .pnp.loader.mjs: 8.0K yarn.lock: 292K .yarn: 38M | yarn.lock: 292K node_modules: 164M cache: 34M | yarn.lock: 292K node_modules: 156M |
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_modes |
| ) | Satsteby | ||
| 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/