首页 > 其他分享 >pnpm 是如何颠覆 npm 和 yarn 的?

pnpm 是如何颠覆 npm 和 yarn 的?

时间:2024-11-26 09:55:20浏览次数:9  
标签:npm node 依赖 modules yarn pnpm 安装

今天研究了一下 pnpm 的机制,发现它确实很强大,甚至可以说对 yarnnpm 形成了降维打击 。

我们从包管理工具的发展历史,一起看下到底好在哪里?

npm2

在 npm 3.0 版本之前,项目的 node_modules 会呈现出嵌套结构,也就是说,我安装的依赖、依赖的依赖、依赖的依赖的依赖...,都是递归嵌套的

node_modules
├─ express
│  ├─ index.js
│  ├─ package.json
│  └─ node_modules
│     ├─ accepts
│     │  ├─ index.js
│     │  ├─ package.json
│     │  └─ node_modules
│     │     ├─ mime-types
|     |     |   └─ node_modules
|     |     |      └─ mime-db
|     │     └─ negotiator
│     ├─ array-flatten
│ 		├─ ...
│  		└─ ...
└─ A
   ├─ index.js
   ├─ package.json
   └─ node_modules
      └─ accepts
         ├─ index.js
         ├─ package.json
         └─ node_modules
            ├─ mime-types
            |   └─ node_modules
            |      └─ mime-db
            └─ negotiator

设计缺陷

这种嵌套依赖树的设计确实存在几个严重的问题

  1. 路径过长问题: 由于包的嵌套结构 , node_modules 的目录结构可能会变得非常深,甚至可能会超出系统路径长度上限 ,毕竟 windows 系统的文件路径默认最多支持 256 个字符
  2. 磁盘空间浪费: 多个包之间难免会有公共的依赖,公共依赖会被多次安装在不同的包目录下,导致磁盘空间被大量浪费 。比如上面 express 和 A 都依赖了 accepts,它就被安装了两次
  3. 安装速度慢:由于依赖包之间的嵌套结构,npm 在安装包时需要多次处理和下载相同的包,导致安装速度变慢,尤其是在依赖关系复杂的项目中

当时 npm 还没解决这些问题, 社区便推出了新的解决方案 ,就是 yarn。 它引入了一种新的依赖管理方式——扁平化依赖。

看到 yarn 的成功,npm 在 3.0 版本中也引入了类似的扁平化依赖结构

yarn

yarn 的主要改进之一就是通过扁平化依赖结构来解决嵌套依赖树的问题,具体来说

铺平,yarn 尽量将所有依赖包安装在项目的顶层 node_modules 目录下,而不是嵌套在各自的 node_modules 目录中。

这样一来,减少了目录的深度,避免了路径过长的问题 ,也尽可能避免了依赖被多次重复安装的问题

我们可以在 yarn-example 看到整个目录,全部铺平在了顶层 node_modules 目录下,展开下面的包大部分是没有二层 node_modules

然而,有些依赖包还是会在自己的目录下有一个 node_modules 文件夹,出现嵌套的情况,例如 yarn-example 下的http-errors 依赖包就有自己的 node_modules,原因是:

当一个项目的多个依赖包需要同一个库的不同版本时,yarn 只能将一个版本的库提升到顶层 node_modules 目录中。 对于需要这个库其他版本的依赖,yarn 仍然需要在这些依赖包的目录下创建一个嵌套的 node_modules 来存放不同版本的包

比如,包 A 依赖于 lodash@4.0.0,而包 B 依赖于 lodash@3.0.0。由于这两个版本的 lodash 不能合并,yarn 会将 lodash@4.0.0 提升到顶层 node_modules,而 lodash@3.0.0 则被嵌套在包 B 的 node_modules 目录下。

幽灵依赖

虽然 yarn 和 npm 都采用了扁平化的方案来解决依赖嵌套的问题,但这种方案本身也有一些缺陷,其中幽灵依赖是一个主要问题。

幽灵依赖,也就是你明明没有在 package.json 文件中声明的依赖项,但在项目代码里却可以 require 进来

这个也很容易理解,因为依赖的依赖被扁平化安装在顶层 node_modules 中,所以我们能访问到依赖的依赖

但是这样是有隐患的,因为没有显式依赖,未来某个时候这些包可能会因为某些原因消失(例如新版本库不再引用这个包了,然后我们更新了库),就会引发代码运行错误

浪费磁盘空间

而且还有一个问题,就是上面提到的依赖包有多个版本的时候,只会提升一个,那其余版本的包不还是复制了很多次么,依然有浪费磁盘空间的问题

那社区有没有解决这俩问题的思路呢? pnpm 就是其中最成功的一个

pnpm

pnpm 通过全局存储和符号链接机制从根源上解决了依赖重复安装和路径长度问题,同时也避免了扁平化依赖结构带来的幽灵依赖问题

pnpm 的优势概括来说就是“快、准、狠”:

  • 快:安装速度快
  • 准:安装过的依赖会准确复用缓存,甚至包版本升级带来的变化都只 diff,绝不浪费一点空间
  • 狠:直接废掉了幽灵依赖

执行 npm add express,我们可以在 pnpm-example 看到整个目录,由于只安装了 express,那 node_modules 下就只有 express

那么所有的(次级)依赖去哪了呢? binggo,在node_modules/.pnpm/目录下,.pnpm/ 以平铺的形式储存着所有的包

三层寻址

  1. 所有 npm 包都安装在全局目录 ~/.pnpm-store/v3/files 下,同一版本的包仅存储一份内容,甚至不同版本的包也仅存储 diff 内容。
  2. 顶层 node_modules 下有 .pnpm 目录以打平结构管理每个版本包的源码内容,以硬链接方式指向 pnpm-store 中的文件地址。
  3. 每个项目 node_modules 下安装的包以软链接方式将内容指向 node_modules/.pnpm 中的包。

所以每个包的寻找都要经过三层结构:node_modules/package-a > 软链接 node_modules/.pnpm/package-a@1.0.0/node_modules/package-a > 硬链接 ~/.pnpm-store/v3/files/00/xxxxxx

这就是 pnpm 的实现原理。官方给了一张原理图,可以搭配食用

前面说过,npm 包都被安装在全局 pnpm store ,默认情况下,会创建多个存储(每个驱动器(盘符)一个),并在项目所在盘符的根目录

所以,同一个盘符下的不同项目,都可以共用同一个全局 pnpm store,绝绝子啊

标签:npm,node,依赖,modules,yarn,pnpm,安装
From: https://www.cnblogs.com/burc/p/18568296

相关文章

  • 解决npm install openai报错
    在下载module时出现错误npminstallopenai(node:25160)MaxListenersExceededWarning:PossibleEventEmittermemoryleakdetected.11closelistenersaddedto[TLSSocket].Useemitter.setMaxListeners()toincreaselimit(Use`node--trace-warnings...`tosho......
  • pnpm -F @opentiny/tiny-engine-controller -F @opentiny/tiny-engine-dsl-vue build
    pnpm-F@opentiny/tiny-engine-controller-F@opentiny/tiny-engine-dsl-vuebuild命令的作用是使用pnpm包管理器对指定的工作区包进行构建。具体来说:pnpm:这是Node.js的包管理器,类似于npm,但更高效,支持工作区(workspace)管理。-F或--filter:这是一个选项,用于筛选特定的工......
  • npm uninstall screenfull --legacy-peer-deps
    下面是解决此错误的几种方法:1.清空缓存在终端中运行下面的命令清空npm缓存:npmcacheclean--force然后重新安装依赖包。2.使用--force在安装或更新命令后面加上 --force 选项,强制解析依赖树并安装依赖包。npminstall--force请注意,这种方法可能会引入不兼容......
  • pnpm 和 npm
    pnpm和npm是JavaScript生态系统中常用的包管理工具,它们各自有不同的特性和优缺点。下面是这两者的详细比较:1. 基本概念npm(NodePackageManager):是Node.js的默认包管理器,提供安装、更新、卸载JavaScript包的功能。使用 package.json 文件来管理项目依赖。pn......
  • Mac 系统终端和vscode终端的pnpm版本和路径不一致问题,而且vscode终端的pnpm没法升级
    系统终端whichpnpm路径是/Users/zhanglinfeng/.nvm/versions/node/v16.19.1/bin/pnpm vscode终端 whichpnpm 路径是/usr/local/bin/pnpm 为了跟系统的一致,需要修改.zshrc文件新的#AddRVMtoPATHforscripting.MakesurethisisthelastPATHvariablec......
  • Hadoop三大组件之YARN(一)
    YARN架构与任务提交流程详解1.YARN的组成架构YARN(YetAnotherResourceNegotiator)是Hadoop生态系统中的一个重要组成部分,主要用于资源管理和调度。YARN的架构主要由以下几个关键组件构成:1.1ResourceManager(RM)ResourceManager是YARN的核心组件,负责整个集群的资源管理......
  • 打造双模兼容npm包:无缝支持require与import
    为了实现一个npm包同时支持require和import,你需要确保你的包同时提供了CommonJS和ES6模块的入口点。这通常是通过在package.json文件中指定main和module字段来实现的,以及在构建过程中生成两种不同模块格式的文件。以下是具体步骤:设置package.json:main字段:指定CommonJS模......
  • Yarn安装与配置指南
    Yarn是一个快速、可靠且安全的JavaScript包管理工具,广泛用于管理JavaScript和TypeScript项目的依赖。本文将介绍如何安装和配置Yarn,以便你能够高效地管理项目的依赖包。一、Yarn简介Yarn是由Facebook开发的包管理工具,它在npm的基础上进行了许多优化,包括更快的安装速度、更好的缓存......
  • 秒懂Yarn:安装与配置教程
    秒懂Yarn:安装与配置教程什么是Yarn?Yarn是一个快速、可靠和安全的包管理工具,旨在改善JavaScript开发者的工作流程。它通过并行化操作和缓存机制显著提升了安装包的速度,并且确保了安装包的一致性和安全性。为什么选择Yarn?速度快:Yarn并行下载和缓存包,使得安装速度更快。安全性:通过......
  • node.js安装与npm镜像源切换
    下载nvm点击进入nvmgit仓库下载nvmwindows用户点击exe文件进行下载。下载完毕之后点击安装包进行安装检查是否安装成功打开windows控制栏输入nvm-v检查是否安装成功使用nvm下载node.js打开控制栏输入nvminstalllatest安装当前node......