pnpm 管理依赖包是如何节省磁盘空间的?
npm 存在的问题
我们经常使用 npm
来管理 node 项目中的包,从 package.json
中读取配置将依赖下载到本地,以保障项目的正常运行。
当项目数量多时,这样的包管理方式会非常的占用电脑内存。由于每个项目都有属于自己的依赖,每个项目都需要安装,即使 npm 会对依赖进行缓存,但是每个项目仍然需要安装到自己的 node_modules
文件夹下,此时每个项目安装的每一份依赖都会在磁盘中保存一份,即使各个项目中依赖的版本可能相同。
pnpm
就是针对以上问题出现的解决方案,它使用统一的仓库来存放项目中的包,在项目中使用硬链接+软连接的方式找到依赖所在磁盘的位置。
硬链接和软连接
想要清晰的知道 pnpm 管理依赖的原理,首先要了解硬链接和软连接、拷贝操作的区别。
拷贝操作会在磁盘中复制一份新的数据
,比如拷贝 a.js 为 a_copy.js,两个文件在拷贝后就互不关联,修改 a.js 不会影响 a_copy.js,删除 a_copy.js 也不会影响 a.js。
硬链接是通过寻址的方式
找到磁盘中的数据,比如新建 b_hard.js 与 b.js 创建硬链接,两者指向的是同一个磁盘数据,所以修改其中一个文件,另一个文件也会发生变化。
软连接就是我们平时常见的创建快捷方式
(文件后面会存在一个向右的小箭头),它只是保存着文件的路径,不可以编辑,直接双击就会找到原始的文件。如果原文件被删除,通过软连接将无法找到磁盘中的数据。
我们可以通过命令来进行连接操作,windows 是这样的
/*拷贝*/ copy a.js a_copy.js
/*硬链接*/ mklink /H b_hard.js b.js
/*软连接*/ mklink c_soft.js c.js
pnpm原理
使用 npm 或者 yarn 时,如果有100个项目,并且所有项目都有一个相同的依赖包,那么在磁盘上就需要保存100份该相同依赖的包
。
如果使用 pnpm,依赖包将被放在统一的位置,当安装包时,其包含的所有文件会硬链接到这个位置,不会另外占用磁盘空间,这样不同项目之间就可以共享相同版本的依赖。
如果对同一依赖包使用相同的版本
,那么磁盘上只有这个依赖包的一份文件,如果对同一依赖包使用不同的版本
,那么只有版本之间不同的文件
被存储起来。
比如 a/b/c 三个项目都使用 axios,axios 的所有文件都保存在 pnpm 上,axios 这些文件对应着磁盘的数据,直接 a/b/c 项目的axios 通过硬链接指向磁盘里的数据。 这样有两个好处:
(1)效率非常高,无需下载、查找缓存解压等操作
(2)节省磁盘空间,每个项目不需要再下载一份
pnpm 依赖包统一保存的位置可以使用命令 pnpm store path
来查看
非扁平的 node_modules 目录
使用 npm 或者 yarn安装的依赖包会将所有的子级依赖全部平铺
到 node_modules 文件夹中,即扁平化的目录结构,这样会导致源码可以访问本来不属于当前项目所设定的依赖包。
比如安装 axios ,同时会安装非常多的其它的库如 form-data,虽然在 package.json 中是没有配置的,但在源代码中可以直接通过require('form-data') 引用
,这样就会有隐患,如果项目某天删除了 axios,form-data 就不存在了。
使用 npm 和 pnpm 分别只安装 axios,npm 会将 axios 所需的其它依赖平铺,而 pnpm 的 node_modules 根目录下只有 axios 和 .pnpm 文件夹,这样就可以避免非主动下载的其它依赖包可随意访问的情况。
如果直接按照这样的层级下载包,可能会带来新的问题,如多个包依赖同一个包时,就会被重复安装。
▾ node_modules
▾ axios
▾ node_modules
▸ form-data
▾ xxx
▾ node_modules
▸ form-data
那 pnpm 是如何做到非扁平化并且不重复安装的呢?答案就是它使用硬链接与软连接结合的方式来与依赖包关联。
在 node_modules 根目录有一个文件夹 .pnpm,这里包含了项目所有依赖。
根目录下 axios 软连接
到 .pnpm 目录下的 axios 文件夹中,展开 .pnpm/axios@16.1 的node_modules 文件夹,其中有 axios 所需的依赖,包含 axios、follow-redirects、form-data、proxy-from-env,其中 axios 硬链接
到磁盘中(即与 pnpm 仓库保存的地址一致),其它文件软连接到 .pnpm 的自身位置。
node_modules 根目录下的依赖
,软连接到 .pnpm 文件夹中,如果有相互依赖的关系,仍然通过软连接,只有找到依赖自身,才会通过硬链接找到磁盘中的位置,这样可以保证同一个项目里不同依赖也不会重复安装,同时不同项目之间的相同依赖也无需在磁盘中存储多份。
pnpm 管理依赖包是如何节省磁盘空间的?的更多相关文章
- 安装VM-TOOLS,解压tar包时提示目录磁盘空间不足
在虚拟机里安装了ubuntu-18.04.4-desktop-amd64,安装VM-TOOLS,解压tar包时提示目录磁盘空间不足. 解决方法一: 打开terminal,输入:sudo apt ins ...
- golang使用vendor目录来管理依赖包
Vendor目录介绍 随着Go 1.5 release版本的发布,vendor目录被添加到除了GOPATH和GOROOT之外的依赖目录查找的解决方案.在Go 1.6之前,你需要手动的设置环境变量GO1 ...
- go module管理依赖包
go mod 最大的好处就是摆脱了GOPATH这个限制,在除了GOPATH以外的目录下也能开展你的项目 go mod使用: 1,确保你的go版本是1.1以上 2,创建一个项目目录example,并添加 ...
- Vue笔记:使用 Yarn 管理依赖包
上年10月份, Facebook 发布了新的 node.js 包管理器 Yarn 用以替代 npm ,它比npm更快.更高效. Yarn VS npm 1.yarn.lock 文件 在 npm 中同样 ...
- 017-通过govendor管理依赖包
1:安装 go get -u github.com/kardianos/govendor 2:配置环境变量 需要把 $GOPATH/bin/ 加到 PATH 中 D:\my_workspace\go_ ...
- 引入HBase依赖包带来的麻烦
在一个项目里用到HBase做底层存储,使用maven来管理相关Jar包依赖,用maven来管理依赖包,特别不爽的就是他会将你引入Jar包自己的依赖都搞进来,经常会出现一些类和方法冲突找不到等状况.这次 ...
- 有关项目依赖包发生 Manifest Merge 冲突的详细解决方案
安卓开发使用 Gradle 插件管理依赖包确实非常方便,尤其是在解决一些依赖冲突的问题上.比如,重复依赖的问题,具体内容请我之前写的一篇文章: 有关 Android Studio 重复引入包的问题和解 ...
- go mod 无法自动下载依赖包的问题
go 11以后启用了go mod功能,用于管理依赖包. 当执行go mod init生成go.mod文件之后,golang在运行.编译项目的时候,都会检查依赖并下载依赖包. 在启动了go mod之后, ...
- 为什么在SpringBoot+maven的项目中,所引入的依赖包可以不指定依赖的版本号?
当在Springboot项目中引入了spring-boot-starter-parent,则可以不用引入依赖包版本号,比如: <parent> <groupId>org.spr ...
- Elasticsearch 5.0 磁盘空间节省策略的认识
前言:本文是当时QQ群员讨论磁盘空间如何优化,我搜了下类似的文章,结合官方文档做了一些总结 参考文章1 参考文章2 如果你有疑问,可以联系我参与讨论,或者去原文查看. NOTE: 磁盘空间节省问题,是 ...
随机推荐
- sql-lab通关
page1-less1-22 联合查询 第一关 发现是有回显的,且传入的参数是通过'1'包裹的,所以我们的payload,如下 测试列数 ?id=1' order by 3 --+ //超过第一条语句 ...
- ubuntu安装rpm格式包
首先,我们要安装alien这一软件: $sudo apt-get install alien ##alien默认没有安装,所以首先要安装它 $sudo alien xxxx.rpm ##将rpm转换为 ...
- gitlab-runner-config-in-docker
gitlab in docker 网上有很多现成的解决方案,本文仅作流程梳理,若不需要,可直接用gitlab官方提供的镜像 installation Dockerfile FROM registry. ...
- TCP四次挥手会经历这么多状态
TCP三次握手 中讲述了序列号和建立连接,这一篇来说说释放连接. 标志位 TCP首部中在属性标志位,和建立连接.释放连接有关,位于保留和窗口字段中间,其中三个标识与断开连接有关. ACK: ackno ...
- 在webpack中这样分离环境和代码就好啦
前面的文章中,webpack.config.js 中包含本地调试和线上发布的所有配置,编译后的 bundle.js 包含所有的代码. 当项目变大.代码量变多.配置增加的时候,文件的可维护性会越来越差, ...
- Win11和Win10怎么禁用驱动程序强制签名? 关闭Windows系统驱动强制签名的技巧?
前言 什么是驱动程序签名? 驱动程序签名又叫做驱动程序的数字签名,它是由微软的Windows硬件设备质量实验室完成的.硬件开发商将自己的硬件设备和相应的驱动程序交给该实验室,由实验室对其进行测试,测试 ...
- Qt开发思想探幽]QObject、模板继承和多继承
@ 目录 [Qt开发探幽]QObject.模板继承和多继承 1. QObject为什么不允许模板继承: 2.如果需要使用QObject进行多继承的话,子对象引用的父类链至多只能含有一个QObject ...
- 《SQL与数据库基础》18. MySQL管理
目录 MySQL管理 系统数据库 常用工具 mysql mysqladmin mysqlbinlog mysqlshow mysqldump mysqlimport source 本文以 MySQL ...
- 2D KD-Tree实现
KD-tree 1.使用背景 在项目中遇到一个问题: 如何算一个点到一段折线的最近距离~折线的折点可能有上千个, 而需要检索的点可能出现上万的数据量, 的确是个值得思考的问题~ 2.暴力解法 有个比较 ...
- 《Python魔法大冒险》005 魔法挑战:自我介绍机器人
魔法师和小鱼坐在图书馆的一扇窗户旁,窗外的星空闪烁着神秘的光芒.魔法师轻轻地拍了拍小鱼的肩膀. 魔法师: 小鱼,你已经学会了编写简单的魔法程序,现在我要教你如何创造一个有自己思想的机器人,让它能够和我 ...