JavaScript包管理器比较:Npm vs Yarn vs Pnpm

本篇文章带大家了解一下三种javascript包管理器(npmyarnpnpm),并将这三种包管理器进行对比,聊聊npm、yarn、pnpm三者的区别和关联,希望对大家有所帮助,如有问题欢迎指出!

JavaScript包管理器比较:Npm vs Yarn vs Pnpm

包管理器领域的三个主要参与者:

npm

Yarn

高性能 npm (pnpm)

立即学习“Java免费学习笔记(深入)”;

实际上我们已经在所有包管理器中实现了基本相似的功能,因此您很可能会根据非功能性要求来决定使用哪个包管理器,例如安装速度、存储消耗或实际情况。

当然,您选择使用每个包管理器的方式会有所不同,但它们都有基本一致的概念。以上这些包管理器都可以执行以下指令:

读写数据批量安装或更新所有依赖项添加、更新和删除依赖项运行脚本发布包

然而尽管如此,包管理器在底层还是有所不同的。传统上 npmYarn 将依赖项安装在一个平铺的node_modules文件夹中。(这里注意先后顺序,是 yarn 先平铺的,之前 npm 是递归)。但是平铺也会造成一系列的安全问题。

依赖结构的不确定性。扁平化算法本身的复杂性很高,耗时较长。项目中仍然可以非法访问有声明过依赖的包

因此,pnpmnode_modules 文件夹中引入了一些新概念来更高效的存储依赖,。Yarn Berry 甚至通过完全放弃 node_modules 的 (PnP) 模式(另一个文章会具体说明)来走得更远。

JavaScript package简史

最早发布的包管理器是 npm,早在 2010 年 1 月。它就确立了今天包管理器工作的核心原则。但是既然 npm 已经存在 10 多年了,为什么还有其他选择?以下是出现这种情况的一些关键原因:

node_modules 文件夹结构的依赖关系解析算法不同(嵌套 & 平铺、node_modules vs. PnP mode)依赖提升方式不同(hoistinglocking 格式不同(性能都不同,比如 yarn 自己写的那一套)磁盘存储包文件方式不同(空间效率不同)多包项目(又名 workspaces)的支持不同,这会影响 monorepos 的可维护性和速度新工具和命令的需求不同(通过插件和社区工具对可扩展性的需求不同)可配置性和灵活性不同

让我们深入了解一下 npm 崛起后这些方面如何确定的历史,Yarn Classic 如何解决其中的一些问题,pnpm如何扩展这些概念,以及 Yarn Berry 作为 Yarn Classic 的继任者如何打破这些传统的概念和流程。

先驱者 npm

npm 是包管理器的鼻祖。许多人错误地认为 npm 是“Node package manager”的首字母缩写词,但事实并非如此。

它的发布构成了一场革命,因为在此之前,项目依赖项都是手动下载和管理的。npm 引入了诸如文件及其元数据字段、将依赖项存储在node_modules, 自定义脚本, 公共和私有包等等。

2020 年,GitHub 收购了 npm,所以原则上 npm 现在归微软管理。在撰写本文时,最新的主要版本是 v8,于 2021 年 10 月发布。

创新者 Yarn Classic

在 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 年Yarn0 。从那时起,v1.x 系列被认为是旧版,并更名为 Yarn Classic。它的继任者 Yarn v2 (Berry) 现在是更加活跃的开发分支。

更高效的pnpm

pnpm 的第 1 版由 Zoltan Yarn1于 2017 年发布。它是 npm 的替代品,所以如果你有一个 npm 项目,你可以马上使用 pnpm

创建 pnpm 的主要原因是 npmYarn 对于跨项目使用的依赖项存储结构非常冗余。尽管 Yarn Classicnpm 具有速度优势,但它使用相同的依赖解析方法,这对 pnpm 来说是不行的:npmYarn Classic 使用 hoisting 来平铺他们的 node_modules.

pnpm 没有优化之前的结构,而是引入了另一种依赖解决策略:Yarn2。此方法生成的 node_modules 文件夹其实是依赖于全局存储在主文件夹上的 ~/.pnpm-store/ 目录。每个版本的依赖项都物理形式存储在该目录文件夹中一次,构成单一的源地址来节省相当多的磁盘空间。

node_modules 结构是通过使用 symlinks 创建依赖关系的嵌套结构(其中文件夹内每个文件/包都是通过Yarn3存储)官方文档中的下图阐明了这一点。(待填坑:软硬链接)

1.png

Yarn4中可见 pnpm 的影响力:因为他们在Yarn5方面的创新,竞争对手都希望采用 pnpm 的概念,比如Yarn6和包的高效磁盘管理。

Yarn (v2, Berry),用 Plug’n’Play 重新发明的轮子

Yarn7于 2020 年 1 月发布,被宣传为原始 Yarn 的重大升级。Yarn 团队将其称为 Yarn Berry 以更明显地表明它本质上是一个具有新的代码库和新的原则规范的新包管理器。

Yarn Berry 的主要创新是其Yarn8方法,它是作为Yarn9的策略。不是生成node_modules 的策略,而是生成一个带有依赖查找表的文件 .pnp.cjs,因为它是单个文件而不是嵌套的文件夹结构,所以可以更有效地处理依赖。此外,每个包都以高性能 npm (pnpm)0的形式存储在文件夹内来替代 .yarn/cache/,占用的磁盘空间也比 node_modules 少。

所有这些变化如此之快以至于在发布后引起了很大的争议。PnP 这种破坏性的重大更改高性能 npm (pnpm)1以便与其兼容。默认情况下使用全新的 PnP 方法并且恢复到 node_modules 最初并不简单,这导致许多知名开发人员没有加入其中的考虑且高性能 npm (pnpm)2。

此后,Yarn Berry 团队在其后续版本中高性能 npm (pnpm)3为了解决 PnP 的不兼容问题,团队提供了方法来轻松更改默认操作模式。在高性能 npm (pnpm)4的帮助下,切换回传统  node_modules 方法只需要一行配置。

此外,随着时间的推移,JavaScript 生态系统为 PnP 提供了越来越多的支持,正如您在此高性能 npm (pnpm)5中所见,一些高性能 npm (pnpm)6高性能 npm (pnpm)7已经开始采用 Yarn Berry

尽管 Yarn Berry 还很年轻,但它也已经对包管理器领域产生了影响——pnpm 在 2020 年末采用了高性能 npm (pnpm)8。

安装工作流程

首先必须在每个开发人员的本地和 CI/CD 系统上安装包管理器。

npm

npmNode.js 一起提供,因此不需要额外的步骤。除了为您的操作系统下载高性能 npm (pnpm)9外,使用 CLI 工具管理软件版本已成为一种常见做法。在 Node 的上下文中,node_modules文件夹0 或 node_modules文件夹1 已成为非常方便的实用程序。

Yarn Classic 和 Yarn Berry

您可以通过不同的方式node_modules文件夹2,例如,作为 npm 包来安装:.$ npm i -g yarn

要从node_modules文件夹3,推荐的方法是:

安装或更新 Yarn Classic 到最新的版本

使用命令升级到最新的现代版本

yarn set version berry

但是,在此node_modules文件夹4方法是通过 Corepack。

node_modules文件夹5是由 Yarn Berry 的开发者创建的。该计划最初被命名为node_modules文件夹6 ?,并在 LTS v16 中node_modules文件夹7

在 Corepack 的帮助下,因为 Node 包含 Yarn ClassicYarn Berrypnpm 二进制文件所以您不必“单独”安装的 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

您可以将 pnpm 作为 npm包来安装: $ npm i -g pnpm。您还可以node_modules文件夹8 : 

$ corepack prepare pnpm@6.24.2 --activate

项目结构

在本节中,您将一目了然地看到不同包管理器的主要特征。您可以轻松发现配置特定包管理器涉及哪些文件,以及哪些文件是由安装步骤生成的。

所有包管理器都将所有重要的元信息存储在项目清单node_modules文件夹9文件中。 此外,根级别的配置文件可以被用来设置不同的私有包或者不同的依赖项解析配置。

在安装步骤中,依赖项 dependencies 被存储在文件结构中,例如 node_modules 并生成锁定文件 locking。本节不考虑事实并非如此0,因此所有示例仅显示存储依赖项的单个位置。

npm

使用$ npm install 或较短的 $ npm i 会生成一个 package-lock.json 文件和一个 node_modules 文件夹。还有 .npmrc 这种可配置的文件可以放在根级别目录里面。有关 locking 文件的更多信息,请参阅下一节。

.├── node_modules/├── .npmrc├── package-lock.json└── package.json

yarn

运行 $ 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: node_modules

因为这种特殊的安装模式,比使用其他包管理器您必须在 Yarn Berry 项目中处理更多的文件和文件夹。有些是可选的,有些是强制性的。

Yarn Berry 不再支持 .npmrc 或者 .yarnrc;他需要一个 事实并非如此1。对于传统的生成 node_modules 文件夹的工作流程,您必须提供 nodeLinker 配置来使用 node_modules 或者 pnpm 的配置(这块没看懂)。

# .yarnrc.ymlnodeLinker: 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

yarn berry: pnp

无论是对于PnP 的严格模式还是松散模式,跟着 .pnp.cjsyarn.lock 来执行 $ yarn 都会生成一个 .yarn/cache/ 还有 .yarn/unplugged。PnP strict 是默认模式,如果想要配置 loose 模式,需要如下形式开启⬇️:

# .yarnrc.ymlnodeLinker: pnppnpMode: 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`

pnpm

npmYarn Classic 项目的初始状态一样,pnpm 也需要 package.json 文件。使用 $ pnpm i 安装依赖项后,会生成一个 node_modules 文件夹,但由于其内容是可寻址存储方式,其结构完全不同。

pnpm 还会生成自己的锁定文件 pnp-lock.yml。 您可以使用可选文件 .npmrc 提供附加配置。

Calliper 文档对比神器 Calliper 文档对比神器

文档内容对比神器

Calliper 文档对比神器 28 查看详情 Calliper 文档对比神器

.├── node_modules/│   └── .pnpm/├── .npmrc├── package.json└── pnpm-lock.yml

锁定文件和依赖存储

如上一节所述,每个包管理器都会创建事实并非如此2。

lock 文件准确存储您的项目安装的每个依赖项的版本从而实现更可预测和确定性的安装。因为依赖版本很可能使用事实并非如此3声明(例如,≥ v1.2.5)所以这个 lock 文件是很重要的,如果您不“lock”您的版本,实际安装的版本可能会有所不同。

锁定文件有时也存储校验和(我记得是一段hash),我们将在安全部分更深入地介绍。

npm v5+ 开始锁定文件一直是 npm 主要的功能 ( package-lock.json ) ,pnpm 里是 pnpm-lock.yaml ,在 Yarn Berry 中的 yarn.lock 以新的 YAML 格式出现。事实并非如此4

在上一节中,我们看到了传统方法,将依赖项安装在 node_modules 文件夹结构中。这是 npm、事实并非如此5 和 事实并非如此6都使用的方案,(其中 pnpm 比其他方案更有效)。

Yarn Berry 在 PnP 模式下的做法有所不同。依赖项不是 node_modules 文件夹,而是以 zip 文件的形式存储为 .yarn/cache/.pnp.cjs 文件的组合。

最好将事实并非如此7因为每个团队成员都安装相同的版本,所以它解决了“在你和我的机器上工作”问题。

CLI

下表比较了 npmYarn ClassicYarn Berrypnpm 中可用的不同 CLI 命令。这绝不是一个完整的列表,而是一个备忘单。本节不涉及与workflow 相关的命令。

npmpnpm 具有许多特别的命令和选项别名,这意味着命令可以有不同的名称,即$ npm install$ npm add。 此外,许多命令选项都有缩写版本,例如 -D 来代替 --save-dev。在表格中,我将所有缩写版本称为别名。使用这些包管理器,您都可以增加、更新或删除多个依赖项。

依赖配置管理

此表涵盖了用于安装或更新 package.json 中指定的所有依赖项的依赖项管理命令。

Action npm Yarn Classic Yarn Berry pnpm

install deps in package.jsonnpm install alias: i, addyarn install or yarnlike Classicpnpm install alias: iupdate deps in package.json acc. semvernpm update alias: up, upgradeyarn upgradeyarn semver up (via plugin)pnpm update alias: upupdate deps in package.json to latestN/Ayarn upgrade –latestyarn uppnpm update –latest alias: -Lupdate deps acc. semvernpm update reactyarn upgrade reactyarn semver up reactpnpm up reactupdate deps to latestnpm update react@latestyarn upgrade react –latestyarn up reactpnpm up -L reactupdate deps interactivelyN/Ayarn upgrade-interactiveyarn upgrade-interactive (via plugin)$ pnpm up –interactive alias: -iadd runtime depsnpm i reactyarn add reactlike Classicpnpm add reactadd dev depsnpm i -D babel alias: –save-devyarn add -D babel alias: –devlike Classicpnpm add -D babel alias: –save-devadd deps to package.json without semvernpm i -E react alias: –save-exactyarn add -E react alias: –exactlike Classicpnpm add -E react alias: –save-exactuninstall deps and remove from package.jsonnpm uninstall react alias: remove, rm, r, un, unlinkyarn remove reactlike Classicpnpm remove react alias: rm, un, uninstalluninstall deps w/o update of package.jsonnpm uninstall –no-saveN/AN/AN/A

安装配置管理

下面的例子展示了如何在开发期间管理包。表中使用的术语:

Package: dependency or binaryBinary: 一种执行工具来自 node_modules/.bin/ 或者 .yarn/cache/ (PnP)

重要的是要理解,Yarn Berry 只允许我们执行在 package.json 中或者暴露在 bin/ 文件中的指定的二进制文件。

Action npm Yarn Classic Yarn Berry pnpm

install packages globallynpm i -g ntl alias: –globalyarn global add ntlN/A (global removed)pnpm add –global ntlupdate packages globallynpm update -g ntlyarn global upgrade ntlN/Apnpm update –global ntlremove packages globallynpm uninstall -g ntlyarn global remove ntlN/Apnpm remove –global ntlrun binaries from terminalnpm exec ntlyarn ntlyarn ntlpnpm ntlrun binaries from scriptntlntlntlntldynamic package executionnpx ntlN/Ayarn dlx ntlpnpm dlx ntladd runtime depsnpm i reactyarn add reactlike Classicpnpm add reactadd dev depsnpm i -D babel alias: –save-devyarn add -D babel alias: –devlike Classicpnpm add -D babel alias: –save-devadd deps to package.json without semvernpm i -E react alias: –save-exactyarn add -E react alias: –exactlike Classicpnpm add -E react alias: –save-exactuninstall deps and remove from package.jsonnpm uninstall react alias: remove, rm, r, un, unlinkyarn remove reactlike Classicpnpm remove react alias: rm, un, uninstalluninstall deps w/o update of package.jsonnpm uninstall –no-saveN/AN/AN/A

常用命令

该表涵盖了一些有用的内置命令。如果没有官方的命令,通常可以通过 npm 包或 Yarn Berry 插件来使用第三方命令。

Action npm Yarn Classic Yarn Berry pnpm

发包npm publishyarn publishyarn npm publishpnpm publishlist installed depsnpm ls alias: list, la, llyarn list
pnpm list alias: lslist outdated depsnpm outdatedyarn outdatedyarn upgrade-interactivepnpm outdatedprint info about depsnpm explain ntl alias: whyyarn why ntllike Classicpnpm why ntlinit projectnpm init -y npm init (interactive) alias: –yesyarn init -y yarn init (interactive) alias: –yesyarn initpnpm init -y pnpm init (interactive) alias: –yesprint licenses infoN/A (via third-party package)yarn licenses listN/A (or via plugin, other plugin)N/A (via third-party package)update package manager versionN/A (with third-party tools, e.g., nvm)with npm: yarn policies set-version 1.13.0with Corepack: yarn set version 3.1.1N/A (with npm, Corepack)perform security auditnpm audityarn audityarn npm auditpnpm auditadd deps to package.json without semvernpm i -E react alias: –save-exactyarn add -E react alias: –exactlike Classicpnpm add -E react alias: –save-exactuninstall deps and remove from package.jsonnpm uninstall react alias: remove, rm, r, un, unlinkyarn remove reactlike Classicpnpm remove react alias: rm, un, uninstalluninstall deps w/o update of package.jsonnpm uninstall –no-saveN/AN/AN/A

配置文件

配置包管理器发生在您的 package.json 和专用的配置文件中。

定义要使用的准确版本使用特定的依赖解决策略配置私有注册表告诉包管理器在哪里可以找到 monorepo 中的工作区

npm

大多数配置发生在专用配置文件 .npmrc 中。

如果你想使用 npmworkspaces 功能,你必须在 package.json 中添加事实并非如此8来告诉 npm 在哪里可以找到子项目或工作空间的文件夹。

  // ...  "workspaces": [    "hooks",    "utils"  ]}

每个包管理器都可以使用公共 npm 注册表。或许你很可能希望重用它们而不将它们发布到公共注册表。您可以在 .npmrc 文件中执行此操作配置来私有注册表。( 现在基本都有私有源了)

# .npmrc@doppelmutzi:registry=https://gitlab.doppelmutzi.com/api/v4/projects/41/packages/npm/

npm 存在事实并非如此9,最好在文档中查看它们。

yarn

您可以在 package.json 中设置 yarnworkspaces(必须是私有包)。

{  // ...  "private": true,  "workspaces": ["workspace-a", "workspace-b"]}

任何可选配置都进入一个 .yarnrc 文件。一个常见的配置选项是设置一个 yarn-path: 它强制每个团队成员使用指定的二进制版本。yarn-path 指向包含特定 Yarn 版本的文件夹(例如 .yarn/releases/)。您可以使用命令来安装统一的 Yarn Classic 版本(GitHub 收购了 npm0)。

yarn berry

Yarn Berry 中配置 workspaces 和在 Yarn Classic 中的配置方式类似(package.json)。 大多数 Yarn Berry 配置发生在 .yarnrc.yml 中,并且有许多可用的配置选项。GitHub 收购了 npm1

GitHub 收购了 npm2

# .yarnrc.ymlyarnPath: .yarn/releases/yarn-3.1.1.cjs

yarn berry可以用 $> yarn plugin import 这种导入方式来扩展插件(GitHub 收购了 npm3),这个命令也会更新 .yarnrc.yml

# .yarnrc.ymlplugins:  - 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 问题有一个典型的解决方案:GitHub 收购了 npm4。

# .yarnrc.ymlpackageExtensions:  "styled-components@*":    dependencies:      react-is: "*"

pnpm

pnpm 使用与 npm 相同的配置机制,因此您可以使用 .npmrc 文件。配置私有注册表的工作方式也与使用 npm 相同。借助 pnpm 的GitHub 收购了 npm5可以支持多包项目。要初始化 monorepo,您必须在 pnpm-workspace.yaml 文件中指定包GitHub 收购了 npm6。

# pnpm-workspace.yamlpackages:  - 'packages/**'

Monorepo

什么是Monorepo

(这里其实就是三种概念,单仓库多项目,单仓库单项目,多仓库多项目)

monorepo 是一个包含多个项目的存储库,这些项目被称为 workspace 或者包。将所有内容保存在一个地方而不是使用多个存储库是一种项目组织策略。

当然,这会带来额外的复杂性。Yarn Classic 是第一个启用此功能的,但现在每个主要的包管理器都提供了工作区功能。本节展示如何使用每个不同的包管理器配置工作区。

npm

npm 团队在 v7 中发布了期待已久的GitHub 收购了 npm7它包含许多 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 目前不支持高级过滤或并行执行多个与工作区相关的命令。

yarn

2017 年 8 月,Yarn 团队GitHub 收购了 npm8GitHub 收购了 npm9功能方面提供 monorepo 支持。最新的主要版本是 v80等第三方软件的多包项目中使用包管理器。Yarn 的这一新增功能也为其他包管理器实现此类功能铺平了道路。

如果你有兴趣,可以参考最新的主要版本是 v81但是这篇文章只会介绍一些必要的命令,以帮助您管理 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 Berry 从一开始就最新的主要版本是 v82为特色,因为它的实现是建立在 Yarn Classic 的概念之上的。在最新的主要版本是 v83中,Yarn Berry 的主要开发人员简要概述了面向工作空间的功能,包括:

最新的主要版本是 v84: 可以在安装包时重用来自其他工作区的版本最新的主要版本是 v85:更新所有工作区的包最新的主要版本是 v86:仅为单个工作区安装依赖项最新的主要版本是 v87:在所有工作区上运行命令

Yarn Berry 使用大量可用于 package.json 文件的 dependenciesdevDependencies 字段的最新的主要版本是 v88。其中就有 workspace最新的主要版本是 v89。engineering.fb.com/2016/10/11/…0

Yarn Classic 的工作区相比,Yarn Berry 明确定义依赖项必须是此 monorepo 中的包之一。否则如果版本不匹配,Yarn Berry 可能会尝试从远程注册表获取其版本。

{  // ...  "dependencies": {    "@doppelmutzi/hooks": "workspace:*",    "http-server": "14.0.0",    // ...  }  }

pnpm

通过 workspace 这种协议,pnpm 促成了类似于 Yarn Berrymonorepo 项目。许多 pnpm 命令接受 --recursive (-r) 或者 engineering.fb.com/2016/10/11/…1 这种在 monorepo 上下文中特别有用的选项。它的engineering.fb.com/2016/10/11/…2也是对 Lerna 的一个很好的补充。

# prune all workspaces  pnpm -r exec -- rm -rf node_modules && rm pnpm-lock.yaml  # run all tests for all workspaces with scope @doppelmutzipnpm recursive run test --filter @doppelmutzi/`

性能 & 磁盘效率

性能是选型决策的关键部分。本节展示了基于一个小型和一个中型项目的基准测试。以下是有关示例项目的一些说明:

两组基准都不使用工作区功能小项目指定33个依赖中项目指定44个依赖

我用三个用例 (UC) 对我们的每个包管理器变体进行了一次测量。要了解详细的评估和解释,请查看engineering.fb.com/2016/10/11/…3和engineering.fb.com/2016/10/11/…4的结果。

UC 1:没有缓存/存储,没有锁定文件,没有 node_modules.pnp.cjsUC 2:存在缓存/存储,没有锁定文件,没有 node_modules.pnp.cjsUC 3:存在缓存/存储,存在锁定文件,没有 node_modules.pnp.cjs

我使用工具engineering.fb.com/2016/10/11/…5来测量安装消耗的时间( yarn | gnomon )。此外我测量了生成文件的大小 $ du -sh node_modules

Performance results for Project 1

Methodnpm v8.1.2Yarn Classic v1.23.0pnpm v6.24.4Yarn Berry PnP loose v3.1.1Yarn Berry PnP strict v3.1.1Yarn Berry node_modules v3.1.1Yarn Berry pnpm v3.1.1UC 186.63s108.89s43.58s31.77s30.13s56.64s60.91sUC 241.54s65.49s26.43s12.46s12.66s46.36s40.74sUC 323.59s40.35s20.32s1.61s1.36s28.72s31.89sFiles and sizepackage-lock.json: 1.3M node_modules: 467Mnode_modules: 397M yarn.lock: 504Kpnpm-lock.yaml: 412K node_modules: 319Myarn.lock: 540K cache: 68M unplugged: 29M .pnp.cjs: 1.6Myarn.lock: 540K cache: 68M unplugged: 29M .pnp.cjs: 1.5Mnode_modules: 395M yarn.lock: 540K cache: 68Mnode_modules: 374M yarn.lock: 540K cache: 68M

Performance results for Project 2

Methodnpm v8.1.2Yarn Classic v1.23.0pnpm v6.24.4Yarn Berry PnP loose v3.1.1Yarn Berry PnP strict v3.1.1Yarn Berry node_modules v3.1.1Yarn Berry pnpm v3.1.1UC 134.91s43.26s15.6s13.92s6.44s23.62s20.09sUC 27.92s33.65s8.86s7.09s5.63s15.12s14.93sUC 35.09s15.64s4.73s0.93s0.79s8.18s6.02sFiles and sizepackage-lock.json: 684K node_modules: 151Myarn.lock: 268K node_modules: 159Mpnpm-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: 38Myarn.lock: 292K node_modules: 164M cache: 34Myarn.lock: 292K node_modules: 156M cache: 34M

安全

npm

npm 在处理坏包时有点过于宽容并且遇到了一些直接影响许多项目的安全漏洞。例如,在 5.7.0 版本中,当您在 Linux 操作系统上执行 sudo npm 命令时,可以engineering.fb.com/2016/10/11/…6,从而导致操作系统无法使用。

engineering.fb.com/2016/10/11/…7发生在 2018 年,涉及比特币被盗。 Node.js 包engineering.fb.com/2016/10/11/…8在其 3.3.6 版本中添加了恶意依赖项。这个恶意包包含一个加密方法试图从开发者的机器上窃取比特币。

为了帮助解决这些问题,新的 npm 版本使用engineering.fb.com/2016/10/11/…9来检查您安装的软件包的完整性。Yarn0。

yarn

Yarn ClassicYarn Berry 从一开始就使用Yarn1来检验每一个包的完整性。Yarn 还试图阻止您检索在 package.json 中未声明的恶意包:如果发现不匹配,则中止安装。

PnP 模式下的 Yarn Berry 没有传统 node_modules 方式的安全问题。与 Yarn Classic 相比,Yarn Berry 提高了命令执行的安全性。您只能执行已在 package.json 声明的包。此安全功能类似于 pnpm,我将在下面进行描述。

pnpm

pnpm 还是Yarn2来验证每个已安装包的完整性,然后再执行其代码。

正如我们在上面提到的,npmYarn Classic 都存在Yarn3。pnpm 避免了这种情况,因为它的管理模型不使用提升;相反,它会生成嵌套 node_modules 文件夹,从而消除非法依赖访问的风险。这意味着依赖关系都在 .package.json 中声明了。

正如我们所讨论的,这在 monorepo 设置中尤其重要,因为提升算法有时会导致Yarn4。

热门项目使用情况

npmYarn ClassicYarn BerrypnpmSvelteReactJest (with node_modules)Vue 3PreactAngularStorybook (with node_modules)BrowserlistExpress.jsEmberBabel (with node_modules)PrismaMeteorNext.jsRedux Toolkit (with node_modules)SvelteKitApollo ServerGatsby

Nuxt

Create React App

webpack-cli

Emotion

结论

不同的包管理器原理确实存在很大的差异。

pnpm 起初看起来像 npm,因为它们的 CLI 用法相似,但管理依赖项却大不相同;pnpm的方法带来更好的性能和最佳的磁盘空间效率。Yarn Classic 仍然很受欢迎,但它被认为是遗留软件,并且在不久的将来可能会放弃支持。Yarn Berry PnP 是全新的,但人们尚未意识到其再次彻底改变包管理器领域的潜力。

多年来,许多用户询问Yarn5,总体而言人们似乎对 Yarn Berry PnP 的成熟度和采用特别感兴趣。

本文的目的是为您提供多种观点,以决定您自己使用哪个包管理器。我想指出,我不推荐特定的包管理器。这取决于你如何衡量不同的要求——所以你仍然可以选择你喜欢的任何东西!

英文原文地址:https://blog.logrocket.com/javascript-package-managers-compared/

更多node相关知识,请访问:Yarn6!

以上就是JavaScript包管理器比较:Npm vs Yarn vs Pnpm的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/546403.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
程序员的未来属于「伪代码」!Nature专栏:用ChatGPT加速科研编程的三种姿势
上一篇 2025年11月9日 17:56:19
2026年360小说网小说阅读入口 360小说网最新可用官方网站地址
下一篇 2025年11月9日 17:56:25

相关推荐

  • 如何安全有效地从外部网页获取HTML元素数据并应用于自身页面

    本教程旨在解决如何在不同域名下,通过javascript获取并使用另一个网页的html元素数据。文章将深入探讨同源策略的限制,并提供两种主要解决方案:使用` 在现代Web开发中,有时我们需要从外部网站获取特定的HTML内容或属性值,并将其整合到我们自己的网页中。例如,从XYZ.COM/B.html页…

    2026年5月10日
    000
  • PHP中基于用户角色的页面访问控制实践

    本教程详细讲解如何在PHP应用程序中利用会话(Session)机制实现基于用户角色的页面访问控制。通过正确的session_start()调用、用户登录时的角色信息存储,以及在受保护页面进行严格的会话和角色类型检查,确保只有特定用户(如“manager”)才能访问指定页面,从而有效防止未经授权的访问…

    2026年5月10日
    100
  • 全栈JS代码怎么结构化_全栈JavaScript项目代码结构与规范指南

    采用分层+功能划分的目录结构,明确分离前后端代码;2. 遵循单一职责原则,路由、控制器、服务与模型各司其职;3. 统一命名规范并集成ESLint+Prettier保证代码风格一致;4. 使用环境变量管理配置,通过脚本实现自动化构建与并发启动服务。 全栈JavaScript项目涉及前端、后端、数据库交…

    2026年5月10日
    000
  • Chart.js多轴混合图表实现指南:结合柱状图与折线图并正确配置轴标签

    本文详细介绍了如何使用chart.js创建包含柱状图和折线图的多轴混合图表。重点阐述了数据结构定义、自定义背景图案函数以及chart.js scales配置项的正确使用,特别是如何为不同数据集分配独立的y轴,并确保轴标签的正确显示和定位,从而解决多轴图表配置中的常见问题。 在数据可视化中,我们经常需…

    2026年5月10日
    000
  • JavaScript模块化开发有哪些方法?

    JavaScript模块化开发主要有四种方法:1. CommonJS(Node.js默认,同步加载,导出值拷贝);2. AMD(浏览器异步设计,依赖前置);3. CMD(就近依赖,延迟加载);4. ES6 Module(标准规范,静态分析、实时绑定、原生支持,推荐新项目使用)。 JavaScript…

    2026年5月10日
    000
  • html5使用intersection observer实现懒加载 html5使用交叉观察器的技巧

    使用 Intersection Observer API 实现图片懒加载,通过监听元素进入视口并动态加载真实图片,减少资源请求、提升性能;结合 rootMargin 提前加载、多阶段加载和错误处理可进一步优化体验,兼容性不足时可降级至 scroll 事件或引入 polyfill。 在现代网页开发中,…

    2026年5月10日
    000
  • 优化HTML页面box-shadow显示:解决滚动内容区域阴影不完整问题

    在使用bootstrap构建页面时,将`box-shadow`直接应用于`body`元素可能导致当页面内容超出浏览器视口高度时,阴影效果在滚动时显示不完整。本教程将深入分析这一问题,并提供一个通过调整css样式,将`box-shadow`应用到`main`内容区域的解决方案,以确保阴影效果能随着内容…

    2026年5月10日
    000
  • JavaScript Flow类型检查

    Flow是Facebook开发的JavaScript静态类型检查工具,通过在文件顶部添加// @flow注释启用,支持逐步集成。安装flow-bin后运行npx flow init初始化配置,并在package.json中添加flow脚本。它提供number、string、boolean、Array…

    2026年5月10日
    000
  • 如何构建一个高可用的Node.js应用,并处理进程崩溃与重启?

    使用PM2管理进程,处理未捕获异常和Promise拒绝,启用集群模式提升性能与容错,提供健康检查接口配合外部监控,确保Node.js应用高可用。 构建一个高可用的 Node.js 应用,关键在于进程管理、错误处理和自动恢复机制。Node.js 是单线程事件循环模型,一旦主线程崩溃,整个服务就会中断。…

    2026年5月10日
    200
  • 在HTML文件中嵌入Mermaid图表教程

    本教程详细介绍了如何在HTML文件中直接嵌入和渲染Mermaid图表。通过引入Mermaid CDN库并进行简单的初始化配置,用户可以轻松地在网页中展示流程图、时序图、甘特图等多种类型的图表,无需依赖外部工具或复杂的构建流程,实现图表内容的动态化与可视化。 引言:Mermaid图表与HTML集成 M…

    2026年5月10日
    100
  • 如何在点击的Div中获取正确的ID

    本文旨在解决动态生成的HTML元素中,点击事件发生时,如何准确获取与该元素关联的ID值的问题。通过事件委托和DOM遍历,我们将提供一种可靠的方法,确保在复杂的动态环境中,始终能获取到正确的ID,避免因选择器错误而导致的数据获取错误。 在动态生成的HTML结构中,经常会遇到点击事件需要获取特定ID的情…

    2026年5月10日
    000
  • JS插件如何实现模块化_JS插件模块化开发方法与最佳实践

    采用ES6模块化规范可提升JS插件的可维护性与复用性,通过合理拆分功能模块、设计可配置接口并结合构建工具打包发布,实现高效协作与多环境兼容。 在现代前端开发中,JS插件的模块化不仅能提升代码可维护性,还能增强复用性和协作效率。实现模块化的关键在于合理组织代码结构、使用标准模块规范,并遵循清晰的设计原…

    2026年5月10日
    000
  • Express.js 应用中跨模块共享与修改全局数组的教程

    在Express.js应用中,当需要在主应用文件与独立的路由模块之间共享并修改一个全局数组时,`app.locals`提供了一种简洁有效的解决方案。本文将详细介绍如何利用`app.locals`在`index.js`中定义一个数组,并在路由处理函数(如`module.js`)中安全地访问和更新该数组…

    2026年5月10日
    100
  • 解决 Angular 14 升级至 16 后第三方依赖兼容性错误与最佳实践

    将 Angular 应用从版本 14 升级到 16 时,常见的挑战是处理第三方库的兼容性问题,尤其是在使用 `–force` 标志后可能导致大量编译错误。本文将提供一套系统的解决方案,包括识别过时依赖、逐一验证库兼容性、遵循官方升级指南,并强调避免强制安装以确保平滑升级,最终实现稳定运行…

    2026年5月10日
    100
  • React Native 应用中批量下载并管理PDF文件以支持离线访问

    本文详细介绍了在react native应用中实现批量pdf文件下载以支持离线访问的最佳实践。我们将探讨如何利用`react-native-blob-util`等库高效下载大量pdf文件,并结合`react-native-fs`进行本地存储管理。内容涵盖了从安装配置、代码示例到批量下载策略、存储优化…

    2026年5月10日
    000
  • 解决Bootstrap按钮间非预期空白间距的专业指南

    在bootstrap布局中,并排按钮之间出现无法通过常规css检查工具定位的空白间距,通常并非css样式问题,而是html源代码中元素间的换行符或空格所导致。这些空白符被浏览器解析为单个空格,进而创建了视觉上的间距。 理解问题根源:HTML空白字符的处理 当HTML元素(尤其是display: in…

    2026年5月10日
    000
  • PHP如何实现动态图表_PHP动态图表生成的方法与代码实例

    PHP通过结合前端图表库实现动态图表生成,常用方法包括:1. 使用Chart.js与Ajax获取PHP输出的JSON数据绘制柱状图;2. 利用Google Charts在前端嵌入PHP生成的JSON数据展示折线图;3. 通过ECharts调用PHP接口返回的数据渲染交互式饼图。核心是PHP处理数据并…

    2026年5月10日
    000
  • JavaScript RESTful API设计与实现

    答案:使用Node.%ignore_a_1%和Express可快速构建RESTful API,通过GET、POST、PUT、DELETE操作实现用户资源的增删改查,结合路由模块化、统一响应格式、输入验证与错误处理提升API质量,确保语义清晰、结构规范、易于维护。 在现代Web开发中,JavaScri…

    2026年5月10日
    000
  • NPM包发布指南:如何正确处理模块间依赖,避免本地tgz文件路径问题

    当发布NPM包时,在`package.json`中使用`file:`协议引用本地`.tgz`依赖是不被支持的。这种做法会导致消费者在安装该包时遇到`package not found`或`ENOENT`等错误,因为NPM期望从注册表解析依赖,而非处理发布包中的本地文件路径。为确保模块正确安装,所有依…

    2026年5月10日
    000
  • HTML结构优化:高效移除标签内的标签

    本教程详细介绍了如何通过编程方式移除HTML文档中嵌套在“标签内的“标签,从而优化HTML结构。文章提供了纯JavaScript(适用于浏览器环境)和Node.js(结合`jsdom`库)两种实现方案,并附带示例代码和关键注意事项,帮助开发者实现更简洁、语义化的网页内容。 HTML结构…

    2026年5月10日
    000

发表回复

登录后才能评论
关注微信