Pnpm:包管理的新星,如何颠覆 Npm 和 Yarn
在探索现代 JavaScript 生态系统时,我们常常会遇到新兴技术的快速迭代和改进。其中,包管理工具的发展尤为重要,因为它们直接影响开发效率和项目性能。最近,pnpm 作为一种新的包管理工具引起了广泛关注。它不仅挑战了传统工具如 npm 和 Yarn,还提供了一些独特的优势,使其在许多方面超越了前辈。
为了更好地理解 pnpm 的优势,我们从包管理工具的历史开始探索,从 npm2 开始的各个阶段。我们将看到 pnpm 如何通过技术创新解决历史遗留问题,并极大地提高性能和效率。接下来,深入了解 pnpm 的核心机制以及它如何改变开发者处理依赖管理的方式。
npm2
使用 Node 版本管理工具将 Node 版本降级到 4,然后 npm 版本将是 2.x。

在一个目录中运行 npm init -y 快速创建一个 package.json 文件。
然后运行 npm install express,express 包及其依赖项将被下载:

展开 express,它也有 node_modules:

继续展开几层,每个依赖项都有自己的 node_modules:

换句话说,npm2 的 node_modules 是嵌套的。
这正常吗?这有什么问题吗?
实际上,这确实有问题。多个包不可避免地具有共同的依赖项。当像这样嵌套时,相同的依赖项将被多次重复,占用了相对较大的磁盘空间。
这还不是最大的问题;致命的问题是 Windows 中文件路径的最大长度超过 260 个字符。像这样嵌套会超过 Windows 的路径长度限制。
在 npm 尚未解决这个问题时,社区出现了一个新的解决方案:yarn。
yarn
Yarn 如何解决重复依赖和过长嵌套路径的问题?
扁平化。所有依赖项不再逐层嵌套,而是全部处于同一层级,因此不再存在重复依赖或路径过长的问题。
我们删除 node_modules,使用 Yarn 重新安装并执行 yarn add express:
此时,node_modules 看起来像这样:

所有依赖项都在同一层级,大多数包在其下没有第二层 node_modules:

当然,有些包仍然有 node_modules,例如这个:

为什么仍然存在嵌套?
因为一个包可能有多个版本,并且只有一个版本可以被提升。因此,当遇到不同版本的同一包时,仍然使用嵌套。
npm 升级到版本 3 后,也采用了这种扁平化解决方案,与 yarn 非常相似:

当然,yarn 也实现了 yarn.lock 的功能来锁定依赖项版本,但 npm 也实现了这一点。
yarn 和 npm 都采用了扁平化解决方案。这种方法没有问题吗?
不完全是,扁平化解决方案也有自己的问题。
主要问题是幽灵依赖,这意味着在代码中可以引入未在依赖项部分声明的依赖项。
这很容易理解,因为一切都是扁平化的,所以可以找到依赖项的依赖项。
然而,这带来了风险,因为没有明确的依赖声明,如果有一天另一个包不再依赖于那个包,你的代码将无法运行,因为依赖于它,但现在没有安装。
这就是幽灵依赖的问题。
另一个问题是多个版本的依赖项,如上所述。只有一个版本会被提升,而其他版本则会重复多次,导致磁盘空间浪费。
社区有解决这两个问题的想法吗?
当然有!这就是为什么引入了 pnpm。
pnpm
回顾一下,为什么 npm3 和 yarn 扁平化 node_modules?不就是因为相同的依赖项会被多次重复,并且长路径可能会在 Windows 上引发问题吗?
如果我们不重复它们,而是使用链接呢?
首先,介绍链接。它是操作系统提供的软链接和硬链接。硬链接是同一个文件的不同引用,而符号链接会创建一个新文件,其内容指向另一个路径。当然,这两种链接的使用方式是类似的。
如果不复制文件,而是将 npm 包的唯一副本存储在全局仓库中,并将其他位置链接到它呢?
这样就不会因多次复制而浪费磁盘空间,也不会有路径过长的问题。路径长度的限制本质上意味着不应该有太深的目录层级;现在所有位置的目录是链接在一起的,而不是在同一个目录中,因此没有长度限制。
是的,pnpm 通过这种方法实现了这一点。
再次删除 node_modules,然后使用 pnpm 通过运行 pnpm install 重新安装。
你会注意到它打印出这样一句话:

软件包从全局存储硬链接到虚拟存储,这里的虚拟存储是 node_modules/.pnpm。
我们打开 node_modules 看一看。

确实不是扁平的,依赖 express,所以在 node_modules 下只有 express,没有任何幽灵依赖。
展开 .pnpm 看看:

所有依赖项都在这里解决,全部从全局仓库直接链接过来,并通过符号链接组织包之间的依赖关系。
例如,.pnpm 下的 express,都是符号链接。

换句话说,所有依赖项都是从全局仓库硬链接到 node_modules/.pnpm,然后它们通过符号链接相互依赖。
官方提供了一个示意图,结合起来看很清楚:

这就是 pnpm 的实现原理。
pnpm 的优越性
首先,最大的优势是节省磁盘空间。包只在全局保存一份,其余的都是符号链接或硬链接。这节省了大量磁盘空间。
其次,它很快,因为它使用链接而不是复制,这自然使它更快。
这些也是它所宣称的优势:

相比 npm2,优势在于不会多次重复相同的依赖项。
相比 yarn 和 npm3+,没有幽灵依赖,也没有未提升依赖项的重复问题。
这已经足够优秀,可以说是对 yarn 和 npm 的一次打击。
结语
最近,pnpm 频繁被提及,可以说是当下的趋势。在本文中,我们总结了其受欢迎的原因:
npm2 以嵌套方式管理 node_modules,导致多次重复依赖项的问题。
npm3+ 和 yarn 通过扁平化方式管理 node_modules,解决了嵌套方式的一些问题,但引入了幽灵依赖的问题。此外,同名包只有一个版本被提升,而其他版本仍会重复。
pnpm 通过不复制文件,而是从全局仓库硬链接到 node_modules/.pnpm,并通过符号链接组织依赖关系,解决了这些问题。
这不仅节省了磁盘空间,消除了幽灵依赖问题,还加快了安装速度。从机械角度来看,pnpm 超越了 npm 和 yarn。
通过这种对 npm 和 yarn 的创新方法,pnpm 正在通过简化依赖管理的方式产生影响。
最后:
vue2与vue3技巧合集
VueUse源码解读
相关文章:
Pnpm:包管理的新星,如何颠覆 Npm 和 Yarn
在探索现代 JavaScript 生态系统时,我们常常会遇到新兴技术的快速迭代和改进。其中,包管理工具的发展尤为重要,因为它们直接影响开发效率和项目性能。最近,pnpm 作为一种新的包管理工具引起了广泛关注。它不仅挑战了传统工具如 np…...
汽车IVI中控开发入门及进阶(三十二):i.MX linux开发之Yocto
前言: 对于NXP的i.mx,如果基于linux开发,需要熟悉以下文档: IMX_YOCTO_PROJECT_USERS_GUIDE.pdf IMX_LINUX_USERS_GUIDE.pdf IMX_GRAPHICS_USERS_GUIDE.pdf 如果基于android开发,需要熟悉一下文档: Android_Auto_Quick_Start_Guide.pdf ANDROID_USERS_GUIDE.pdf …...
tessy 编译报错:单元测试时,普通桩函数内容相关异常场景
目录 1,失败现象 2,原因分析 1,失败现象 1,在 step 桩函数正常的情况下报错。 2,测试代码执行的数据流 和 step 桩函数内容不一致。 2,原因分析 桩函数分为 test object, test case, test step 三种类别。…...
计算机专业是否仍是“万金油”
作为一名即将参加高考的学生,我站在人生的分岔路口上,面临着选择大学专业的重大抉择。在这个关键节点,计算机相关专业是否仍是炙手可热的选择? 首先,从行业的角度来看,计算机相关专业确实在近年来持续火…...
雷池社区版自动SSL
正常安装雷池,并配置站点,暂时不配置ssl 不使用雷池自带的证书申请。 安装(acme.sh),使用域名验证方式生成证书 先安装git yum install git 或者 apt-get install git 安装完成后使用 git clone https://gitee.com/n…...
怎样减少徐州服务器租用的成本?
服务器租用的出现,十分便于网络行业的发展,但是随着服务器租用的广泛应用,整体还是有着一定的成本的吗,不同的服务器类型在价格方面也是不同的,那么企业在选择服务器租用后,怎样才能减少服务器租用的成本呢…...
【性能优化】表分桶实践最佳案例
分桶背景 随着企业的数据不断增长,数据的分布和访问模式变得越来越复杂。我们前面介绍了如何通过对表进行分区来提高查询效率,但对于某些特定的查询模式,特别是需要频繁地进行数据联接查或取样的场景,仍然可能面临性能瓶颈。此外…...
数据仓库的挑战
建设数据仓库是一个复杂且资源密集的过程,需要考虑多个方面。以下是建设数据仓库时常见的挑战及其详细解释: 1. 数据集成 挑战: 数据来源多样:数据来自不同的系统、数据库、文件格式(如CSV、JSON、XML)、…...
基于ResNet-18的简单分类(新手,而且网络效果不咋滴,就是学个流程)
引言 先看问题: 我手边有一数据集,然后我想分分类!~~ 咳咳,最近刚做了一个:训练集有1143张,分为5类,里面图片是打乱的。测试集有248张,想把它分分类看看咋样。 再看一下效果: …...
自动化测试:Autorunner的使用
自动化测试:Autorunner的使用 一、实验目的 1、掌握自动化测试脚本的概念。 2、初步掌握Autorunner的使用 二、Autorunner的简单使用 autoRunner使用方法 新建项目 a) 在项目管理器空白区域,右键鼠标,选择新建项目 b) 输入项目名后,点击[确定]. 在初次打开aut…...
时序预测 | Matlab基于CNN-BiLSTM-Attention多变量时间序列多步预测
目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.Matlab基于CNN-BiLSTM-Attention多变量时间序列多步预测; 2.多变量时间序列数据集(负荷数据集),采用前96个时刻预测的特征和负荷数据预测未来96个时刻的负荷数据&…...
软考 系统架构设计师系列知识点之杂项集萃(42)
接前一篇文章:软考 系统架构设计师系列知识点之杂项集萃(41) 第67题 Windows操作系统在图形界面处理方面采用的核心架构风格是( )风格。Java语言宣传的“一次编写,到处运行”的特性,从架构风格…...
FastBoot刷机获取root权限(Magisk)
1.首先要下载ADB、Fastboot等工具。 1.ADB、Fastboot工具 https://developer.android.com/studio/releases/platform-tools 2.安装FastBoot的USB驱动 https://developer.android.com/studio/run/oem-usb 2.下载对应的镜像 https://developers.google.com/android/images?…...
信息检索(43):SPLADE: Sparse Lexical and Expansion Model for First Stage Ranking
SPLADE: Sparse Lexical and Expansion Model for First Stage Ranking 摘要1 引言2 相关工作3 方法3.1 SparTerm3.2 SPLADE:稀疏词汇和扩展模型 4 实验5 结论 发布时间(2021) 标题:稀疏词汇 扩展模型 摘要 稀疏的优点…...
DockerHub 镜像加速
Docker Hub 作为目前全球最大的容器镜像仓库,为开发者提供了丰富的资源。Docker Hub 是目前最大的容器镜像社区,DokcerHub的不能使用,导致在docker下pull镜像无法下载,安装kubernetes镜像也受到影响,下面请看解决方式。 1.加速原理 Docker下载加速的原理…...
Oracle 迁移 Mysql
-- Oracle->MySQL -- 使用时改一下where条件的owner和table_name -- 字段数据类型映射时会将Oracle中的浮点NUMBER转换为decimal(65,8)定点数 -- 可以识别主键约束、非空约束,但无法识别外键约束、唯一约束、自定义check -- 对于Oracle字符串长度为4000的&#x…...
vue3父子组件通信
一,父传子——defineProps 方法: 在父组件的模板中使用子组件标签,并且给标签自定义属性和属性名,即通过v-bind绑定数值,而后传给子组件;子组件则通过defineProps接收使用。 父组件: <tem…...
CSS中使用应用在伪元素中的计数器属性counter-increment
在CSS中,counter-increment 是一个用于递增计数器值的属性。它通常与 counter-reset 和 content 属性一起使用,以在文档中的特定位置(如列表项、标题等)插入自动生成的数字或符号。 counter-increment 基本用法: 使…...
【SkiaSharp绘图08】SKPaint方法:自动换行、是否乱码、字符偏移、边界、截距、文本轮廓、测量文本
文章目录 SKPaint方法BreakText 计算指定宽度内可绘制的字符个数ContainsGlyphs字体是否包含文本字符(是否会乱码)GetGlyphOffsets 字符偏移量GetGlyphPositions 偏移坐标GetGlyphWidths 每个字符的宽度与边界GetHorizontalTextIntercepts 轮廓截距GetPositionedTextIntercepts…...
深入理解Servlet Filter及其限流实践
引言 在Java Servlet技术中,Filter是一个拦截器,它允许开发者在请求到达目标资源之前或响应发送给客户端之后,对请求或响应进行拦截和处理。这种机制为实现诸如身份验证、日志记录、请求修改等功能提供了极大的灵活性。 Filter基础 Filter…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
ardupilot 开发环境eclipse 中import 缺少C++
目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
