您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

关于包管理器Npm、Yarn和Pnpm的一些总结

时间:2023-04-12 11:41:28  来源:微信公众号  作者:前端一码平川

写在前面

在Node.js生态系统中,包管理器是至关重要的组件之一,它们负责维护各种应用程序和库之间的依赖关系。npm是Node.js的默认包管理器,它的初始版本是npm1,但是它很快就被npm2所取代。

npm2

关于npm2最初作为包管理管理,采用的是node_modules嵌套模式,即每个包都会有自己独立的node_modules,且会将各自依赖进行安装,依赖的依赖也会产生自己的node_modules,这样就产生了“嵌套依赖”。

就像回调嵌套一样,容易陷入回调地狱,嵌套依赖也不例外。

这种嵌套依赖的模式,虽然可以使依赖项的版本更加明确和稳定,但是在实际应用中也存在一些问题。其中最大的问题是包的嵌套层级很深,这可能会导致安装和更新依赖项的时间变长,并增加包的大小。此外,由于每个包都有自己的node_modules文件夹,这可能会导致文件系统中出现大量重复的依赖项,从而占用更多的磁盘空间。

在实际操作中,当需要在特定的Node.js版本中使用npm2时,可以使用Node Version Manager (nvm)来管理多个Node.js版本。例如,在切换到Node.js v4.0版本时,对应的npm版本是npm2.x。

图片

为了更好地说明嵌套依赖的问题,我们可以通过安装koa来演示。koa是一个基于Node.js的Web应用程序框架,它有许多依赖项,我们可以使用以下命令来安装koa:

npm install koa

在安装koa时,npm会自动下载和安装所有必需的依赖项,并将它们安装到koa的node_modules文件夹中。如果我们检查koa的node_modules文件夹,我们会发现它包含了大量的依赖项,这些依赖项中又包含了更多的依赖项,导致整个文件夹的嵌套层级变得很深。

图片

对于多包之间会存在公共依赖,如果对于每个依赖都生成自己独立的node_modules,那么就会对相同包重复安装多次,这就会占据很大的磁盘空间。且无限嵌套,也会超过windows的最大文件路径长度限制(265个字符)。

嵌套依赖项的模式是npm2中的一个特性,虽然可以保证依赖项的版本稳定性和精确性,但是它可能会导致嵌套层级变得很深,并占用大量的磁盘空间。

yarn

我们想到,既然树形结构存在弊端,为什么不将依赖包在根node_modules进行扁平化处理,这不就解决了依赖嵌套、依赖重复和路径限制问题了?

此时新方式yarn就横空诞生。

当使用yarn进行依赖管理时,我们可以看到所有依赖都会被安装在根目录下的node_modules文件夹中。与npm2不同的是,yarn采用了扁平依赖项的模式,这意味着相同的依赖包只会被安装一次,并且不会存在多个嵌套的node_modules文件夹。

使用yarn add koa进行安装,可以看到通过yarn进行管理的依赖全部平铺在根node_modules下,且没有重复依赖安装的问题。

图片

但是,当某些依赖包存在多个版本时,yarn会将其中一个版本提升到根node_modules文件夹中,而其他依赖包则会继续维护自己的版本。这可能会导致某些依赖包无法正常工作,因为它们可能需要使用特定版本的依赖包。为了解决这个问题,yarn仍然需要使用嵌套的node_modules文件夹,以确保每个依赖包使用正确的版本。

图片

值得注意的是,yarn采用的扁平依赖项模式具有许多优点,例如更快的安装速度,更少的磁盘空间占用和更少的依赖冲突问题。此外,yarn还提供了一个lock文件,该文件记录了所有依赖项的确切版本和位置,以确保依赖项的版本稳定性和一致性。

yarn的变与不变:

yarn采用了更加高效和可靠的依赖项管理方式,可以有效地避免依赖冲突和嵌套的问题。但是,对于某些多版本依赖包,yarn仍然需要使用node_modules嵌套的方式来确保每个依赖包都使用正确的版本。

npm3

npm3在2015年发布时引入了一种新的依赖项安装算法,称为“扁平依赖项”。其主要原理是通过将所有依赖项都放置在同一个目录下,并使用符号链接来实现依赖项的共享。

在npm3中,所有依赖项都被直接安装到根目录下的node_modules中,而不是像npm2一样在每个依赖包中嵌套一个node_modules目录。这种扁平化的结构可以减少依赖项的嵌套层级,从而降低了磁盘空间的占用和文件路径的长度。在这种模式下,所有依赖项都被安装到顶级node_modules文件夹中,这样就避免了嵌套依赖项的问题。这种模式虽然简单,但是它可能会导致依赖项的版本不稳定,从而可能会导致依赖冲突的问题。

当我们使用npm3安装koa包时,它会首先检查该包所需的所有依赖项是否已经安装,如果没有安装,则会将这些依赖项直接安装到根目录下的node_modules目录中。同时,npm3会使用符号链接将这些依赖项链接到需要使用它们的包的node_modules目录下。

图片

 

 

通过使用符号链接,npm3可以实现依赖项的共享,从而避免了依赖项的重复安装和占用大量的磁盘空间。此外,npm3还支持npm shrinkwrap命令,可以生成一个lockfile文件,记录每个包所使用的依赖项的精确版本号,从而避免了版本冲突和不兼容的问题。

 

shrinkwrap 文件的作用是什么?

这个文件用于记录整个依赖树的结构和依赖包的版本信息,可以保证依赖包的版本稳定性和一致性。

那么使用扁平化方案就能完美解决以上问题吗?当然不是。

  • 幽灵依赖:在声明中没有使用dependencies中的依赖,代码中也可以进行reqiure引入。没有在项目中进行显式依赖,如果别的包不再依赖这个包,就会导致代码因为依赖这个包,而没有进行安装,最终不能正常运行。
  • 磁盘浪费:对于依赖包只会提升一个,存在多个版本时其余包同样得进行拷贝到各自node_modules下,依然会存在磁盘空间浪费。

什么是幽灵依赖?

在安装和使用某个第三方包时,该包依赖的其他依赖没有在它的js文件中显式引入的情况。这些依赖可能在代码中被引用,但是没有被包含在软件包的package.json文件中。这种情况被称为“幽灵依赖”。

举个例子,假设有个项目需要依赖包 A 和 B,而这两个包都依赖于包 C,但是包 A 依赖于包 C 的版本 1.0.0,而包 B 依赖于包 C 的版本 2.0.0。在 npm2 中,这两个版本的包 C 会被分别安装在 A 和 B 的 node_modules 目录下,不会产生冲突。但在 npm3 中,这两个版本的包 C 可能会被安装在同一个 node_modules 目录下,这时候就会产生冲突,导致代码无法运行。

图片

虽然在npm3提供了 npm dedupe 命令,可以是手动输入命令将重复的依赖项合并到顶层 node_modules 目录下,避免了幽灵依赖的问题。但是好像并没有很智能。

总的来说,npm3通过采用扁平化的依赖管理结构和符号链接机制,引入 shrinkwrap 文件实现了依赖项的共享和版本精确控制,并且减少了依赖项的嵌套层级和磁盘空间占用。可以手动使用 dedupe 命令等方式,解决了 npm2 中出现的幽灵依赖问题,提高了包管理的效率和可靠性。

pnpm

针对上面遗留下的两个问题,pnpm横空出世,采用硬链接和符号链接来管理依赖项,以减少重复下载和占用空间,从而有效地解决幽灵依赖和磁盘浪费的问题。

  • 基于内容寻址的文件系统来存储磁盘的文件
  • 不会重复安装同一个包,只在磁盘中写入一次,而后在使用的地方通过hardlink
  • 同包不同版本,也尽可能复用代码

link:也就是软硬连接,这是操作系统提供的机制。

  • 硬连接就是同一个文件的不同引用
  • 软链接是新建一个文件,文件内容指向另一个路径

具体来说,当使用 pnpm 安装koa包的依赖项时,它会首先检查系统上是否已经安装了所需的依赖项。如果已经安装,则 pnpm 将创建一个符号链接到该依赖项,而不是在当前项目中复制该依赖项。这样就避免了重复下载和占用磁盘空间的问题。

我们在命令行输入:

pnpm add koa

图片

图片

此外,pnpm 还支持不同的包引用方式,如路径引用和 git 仓库引用,这使得 pnpm 可以更快地安装依赖项并减少重复下载,从而提高开发效率和依赖项管理的可靠性。通过将包从全局 store 进行硬链接到项目的虚拟 store 中,pnpm 可以避免多次拷贝文件和深度嵌套路径过长的问题,从而进一步减少磁盘空间的占用和提高性能。

图片

PNPM 的核心思想是在整个项目内共享依赖项,而不是每个项目都拥有自己的依赖项副本。

这是官方文档提供的原理图:

图片

可以看到有个公共的依赖包安装池,然后通过软链接引入到各个项目所需要的依赖中,这样就减少了幽灵依赖、依赖嵌套和重复下载的问题。

PNPM的优点如下:

节省磁盘空间:pnpm采用链接的方式将依赖项共享到全局store中,避免了每个项目都需要拷贝一份依赖包的问题,从而显著减少了磁盘占用空间。

提升安装速度:pnpm不需要每次都下载相同的依赖项,而是从全局store中直接链接到各个项目中,因此可以极大地提高安装速度。

避免了幽灵依赖、重复依赖和依赖嵌套:pnpm采用链接的方式,避免了项目之间依赖相同包不一致的问题,同时避免了重复安装相同版本的依赖项和依赖嵌套的问题。

支持多种包引用方式:pnpm支持路径引用和git仓库引用,可以更加灵活地管理依赖项。

天生支持monorepo管理:得益于pnpm的软链接特性,可以在同一个workspace下共享依赖和模块等。

另外,对于存储大量依赖的情况,pnpm提供了「pnpm store prune」命令,可以定期清理不再使用的依赖项,释放磁盘空间。

参考文章

  • 关于现代包管理器的深度思考——为什么现在我更推荐 pnpm 而不是 npm/yarn?
  • pnpm 是凭什么对 npm 和 yarn 降维打击的
  • 现代前端工程为什么越来越离不开 Monorepo?
  • 现代前端工程为什么越来越离不开 Monorepo?
  • 为什么越来越多的项目选择 Monorepo?
  • pnpm官方文档

写在最后

最后对不同包管理器的优缺点、特点做了一些总结:

图片

学而知不足,水平有限,还望诸君多多指教。觉得文章不错的读者,不妨点个关注,收藏起来上班摸鱼的时候品尝。



Tags:包管理器   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
Python 环境包管理器:Anaconda 和 pip 哪个更适合你?
Python环境包管理器是指在Python开发过程中,用于安装、更新、卸载和管理软件包的工具。它们可以帮助开发者更方便地管理Python环境下的各种库和框架。以下是常见的6个Python...【详细内容】
2023-12-06  Search: 包管理器  点击:(152)  评论:(0)  加入收藏
关于包管理器Npm、Yarn和Pnpm的一些总结
写在前面在Node.js生态系统中,包管理器是至关重要的组件之一,它们负责维护各种应用程序和库之间的依赖关系。npm是Node.js的默认包管理器,它的初始版本是npm1,但是它很快就被npm...【详细内容】
2023-04-12  Search: 包管理器  点击:(280)  评论:(0)  加入收藏
在 Ubuntu 中使用轻量的 Apt 软件包管理器 Synaptic
这周推荐的开源软件是 Synaptic。学习这个经过时光积淀的软件包管理器能做哪些现代软件管理器做不到的事情。 来源:https://linux.cn/article-12353-1.html 作者:Abhishek Pr...【详细内容】
2020-06-26  Search: 包管理器  点击:(273)  评论:(0)  加入收藏
PHP包管理器Composer实现原理
Composer是用PHP开发的用来管理项目依赖的工具,当你在项目中声明了依赖关系后,composer可以自动帮你下载和安装这些依赖库,并实现自动加载代码。定义一个composer.json:{ "n...【详细内容】
2019-10-15  Search: 包管理器  点击:(3373)  评论:(0)  加入收藏
「译」 npm 包管理器
npm 包管理器npm is a package manager that comes bundled with Node. Contrary to popular belief npm is not an acronym. According to the npm FAQ It provides an eas...【详细内容】
2019-09-25  Search: 包管理器  点击:(794)  评论:(0)  加入收藏
▌简易百科推荐
Netflix 是如何管理 2.38 亿会员的
作者 | Surabhi Diwan译者 | 明知山策划 | TinaNetflix 高级软件工程师 Surabhi Diwan 在 2023 年旧金山 QCon 大会上发表了题为管理 Netflix 的 2.38 亿会员 的演讲。她在...【详细内容】
2024-04-08    InfoQ  Tags:Netflix   点击:(0)  评论:(0)  加入收藏
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(6)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(13)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(9)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(5)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(11)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(9)  评论:(0)  加入收藏
为什么都说 HashMap 是线程不安全的?
做Java开发的人,应该都用过 HashMap 这种集合。今天就和大家来聊聊,为什么 HashMap 是线程不安全的。1.HashMap 数据结构简单来说,HashMap 基于哈希表实现。它使用键的哈希码来...【详细内容】
2024-03-22  Java技术指北  微信公众号  Tags:HashMap   点击:(11)  评论:(0)  加入收藏
如何从头开始编写LoRA代码,这有一份教程
选自 lightning.ai作者:Sebastian Raschka机器之心编译编辑:陈萍作者表示:在各种有效的 LLM 微调方法中,LoRA 仍然是他的首选。LoRA(Low-Rank Adaptation)作为一种用于微调 LLM(大...【详细内容】
2024-03-21  机器之心Pro    Tags:LoRA   点击:(12)  评论:(0)  加入收藏
这样搭建日志中心,传统的ELK就扔了吧!
最近客户有个新需求,就是想查看网站的访问情况。由于网站没有做google的统计和百度的统计,所以访问情况,只能通过日志查看,通过脚本的形式给客户导出也不太实际,给客户写个简单的...【详细内容】
2024-03-20  dbaplus社群    Tags:日志   点击:(4)  评论:(0)  加入收藏
站内最新
站内热门
站内头条