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 管理依赖包是如何节省磁盘空间的?的更多相关文章

  1. 安装VM-TOOLS,解压tar包时提示目录磁盘空间不足

    在虚拟机里安装了ubuntu-18.04.4-desktop-amd64,安装VM-TOOLS,解压tar包时提示目录磁盘空间不足. 解决方法一: 打开terminal,输入:sudo apt ins ...

  2. golang使用vendor目录来管理依赖包

    Vendor目录介绍 随着Go 1.5 release版本的发布,vendor目录被添加到除了GOPATH和GOROOT之外的依赖目录查找的解决方案.在Go 1.6之前,你需要手动的设置环境变量GO1 ...

  3. go module管理依赖包

    go mod 最大的好处就是摆脱了GOPATH这个限制,在除了GOPATH以外的目录下也能开展你的项目 go mod使用: 1,确保你的go版本是1.1以上 2,创建一个项目目录example,并添加 ...

  4. Vue笔记:使用 Yarn 管理依赖包

    上年10月份, Facebook 发布了新的 node.js 包管理器 Yarn 用以替代 npm ,它比npm更快.更高效. Yarn VS npm 1.yarn.lock 文件 在 npm 中同样 ...

  5. 017-通过govendor管理依赖包

    1:安装 go get -u github.com/kardianos/govendor 2:配置环境变量 需要把 $GOPATH/bin/ 加到 PATH 中 D:\my_workspace\go_ ...

  6. 引入HBase依赖包带来的麻烦

    在一个项目里用到HBase做底层存储,使用maven来管理相关Jar包依赖,用maven来管理依赖包,特别不爽的就是他会将你引入Jar包自己的依赖都搞进来,经常会出现一些类和方法冲突找不到等状况.这次 ...

  7. 有关项目依赖包发生 Manifest Merge 冲突的详细解决方案

    安卓开发使用 Gradle 插件管理依赖包确实非常方便,尤其是在解决一些依赖冲突的问题上.比如,重复依赖的问题,具体内容请我之前写的一篇文章: 有关 Android Studio 重复引入包的问题和解 ...

  8. go mod 无法自动下载依赖包的问题

    go 11以后启用了go mod功能,用于管理依赖包. 当执行go mod init生成go.mod文件之后,golang在运行.编译项目的时候,都会检查依赖并下载依赖包. 在启动了go mod之后, ...

  9. 为什么在SpringBoot+maven的项目中,所引入的依赖包可以不指定依赖的版本号?

    当在Springboot项目中引入了spring-boot-starter-parent,则可以不用引入依赖包版本号,比如: <parent> <groupId>org.spr ...

  10. Elasticsearch 5.0 磁盘空间节省策略的认识

    前言:本文是当时QQ群员讨论磁盘空间如何优化,我搜了下类似的文章,结合官方文档做了一些总结 参考文章1 参考文章2 如果你有疑问,可以联系我参与讨论,或者去原文查看. NOTE: 磁盘空间节省问题,是 ...

随机推荐

  1. .NET Core多线程 (1) Thread与Task

    去年换工作时系统复习了一下.NET Core多线程相关专题,学习了一线码农老哥的<.NET 5多线程编程实战>课程,我将复习的知识进行了总结形成本专题.同时也特别推荐有兴趣的读者去学习一线 ...

  2. 静态vlan的划分

    静态vlan的划分 1,toupu图 2,配置id与子网掩码 2.1,pc,server的ip与子网配置 pc5 pc6 pc7 pc8 server1 server2 3,vlan的静态划分 1,v ...

  3. AVR汇编(二):AVR架构介绍

    AVR汇编(二):AVR架构介绍 ATmega328P介绍 ATmega328P是Atmel公司(现Microchip公司)推出的一个基于AVR架构的高性能低功耗单片机,拥有32KB的Flash.1K ...

  4. 合宙ESP32C3使用PlatformIO开发点亮ST7735S

    开发背景 模块使用的合宙的ESP32-C3(经典款) 购买连接 CORE ESP32核心板是基于乐鑫ESP32-C3进行设计的一款核心板,尺寸仅有21mm*51mm,板边采用邮票孔设计,方便开发者在不 ...

  5. 用了好几年的IDEA主题及配置,拿去吧不谢。

    前言 最近这几年一直用一套IDEA的主题及配置,分享给各位,如果符合你的口味,可以下载了玩玩. 我个人是非常喜欢的,不管是观感还是敲代码都很爽的. 附上一张代码的主题色,大概就是这样子,我个人喜欢清爽 ...

  6. 现代 CSS 解决方案:数学函数 Round

    在 CSS 中,存在许多数学函数,这些函数能够通过简单的计算操作来生成某些属性值,例如在现代 CSS 解决方案:CSS 数学函数一文中,我们详细介绍了 calc():用于计算任意长度.百分比或数值型数 ...

  7. UI自动化项目1说明 | 网页计算器自动化测试项目

    需求: 1.对网页计算器, 进行加法的测试操作. 通过读取数据文件中的数据来执行用例. 2.网址: http://cal.apple886.com/ 测试点: 1.加法:1+1=2 2+9!=10 . ...

  8. 循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(4) -- 实现DataGrid数据的导入和导出操作

    在我们设计软件的很多地方,都看到需要对表格数据进行导入和导出的操作,主要是方便客户进行快速的数据处理和分享的功能,本篇随笔介绍基于WPF实现DataGrid数据的导入和导出操作. 1.系统界面设计 在 ...

  9. DESTOON做中英双语言(多语言)切换版本具体详解

    第一次发原创好激动,该注意点什么? 在开发过程中用户有许多要求,比如这个多语言切换就是一个需求. 首先讲解一下DESTOON(DT)后台系统如何做这个中英.甚至多语言切换的这个功能. DT本身不自带多 ...

  10. Linux系列教程——Shell、Linux文件管理

    文章目录 Shell 1.什么是Bash shell(壳) 2.Bash Shell能干什么? 3.平时我们如何使用Shell呢? 4.Shell提示符 5.Shell基础语法 2.Bash Shel ...