pnpm--他简直是超人!

引言

pnpm是什么?pnpm比npm多个p,比ppnpm少个p,比pppnpm少两个p。。。。好,言归正传,pnpm的p其实是power的意思,意思是pnpm的超级版,超级在哪呢?

诞生背景

pnpm 的诞生源于对现有包管理工具(如 npm 和 Yarn)在性能和资源利用方面的不足的改进需求:

  1. 磁盘空间浪费 :npm 和 Yarn 在安装依赖时会复制所有文件到每个项目的 node_modules,导致重复依赖浪费磁盘空间。
  2. 安装速度慢:传统工具的模块安装速度较慢,尤其是在大型项目中,存在大量重复下载和处理。
  3. 依赖管理问题 :扁平化的 node_modules 结构可能导致依赖冲突,而解决这些冲突需要额外的时间和精力。

pnpm 由 Zoltan Kochan 在 2016 年推出,利用符号链接和硬链接技术,实现共享依赖库,从根本上优化磁盘使用,并显著提升安装速度和一致性,成为现代前端开发的一项重要工具。

总而言之,npm和yarn太拉了,Zoltan Kochan 看不下去了,要把他俩干趴下

了解pnpm的前置知识

硬链接

听名字就知道,很硬,很靠得住,硬在哪?他直接指向硬盘里的文件!炸不炸裂?他直接指向硬盘又说明什么呢?举个例子:假如说我有三个硬链接a,b,c他们都指向某个数据结构,我们删除a,b和c还是指向那块数据结构,再删掉b,c还是指向那块数据结构,只有把所有硬链接都删掉的时候,这个数据结构才从逻辑上被删除了,为什么说逻辑上被删除了?其实物理上,他依旧存在硬盘上(总不可能直接把硬盘那一块扣掉吧),只是没有链接指向他了,这无关紧要,他无法被使用了,就相当于他被删除了,在操作系统的算法中他就是空白,只能等待被其他数据结构覆盖的命运了。

软连接(也叫符号连接)

软连接比硬链接稍微软点,硬链接比软连接稍微硬点。。。。软在哪?他是通过指向目标文件的目录实现的,假如a,b,c都是指向某数据结构的软链接,实际上这三个链接都是指向这个数据结构的路径,我把a删了,操作系统就会把路径删了,因为b和c都是通过该路径指向目标数据结构的,所以b和c也会随之实效。看他这怂样就不好用,它存在的意义是什么?原来因为协议和管理方式的不同,硬链接不能跨文件系统和跨盘指向,而软连接可以,从某种角度来看,软连接就是硬连接的代餐,实在不行才会用他

pnpm-lock.yaml

这个可以讲的非常多,可以参考我另外一篇文章:pnpm.lock.yaml,看似无关紧要,实则······

与yarn和npm的不同之处

存储结构

开发项目时,npm和yarn会把安装的包放在该项目的node_modules目录下,假如有两个项目处于同一文件目录,并且都依赖了一个包,那么npm或者yarn就会把该包放到父文件的node_modules中(父目录有package.json,该依赖包版本一致,hoist机制开启的话),这两个项目直接引用父目录的node_modules,然后两个包的体积就变成了一个包的体积,牛不牛B?这只能算小牛B,hoist有自己的问题:Yarn 和 npm 的 hoist 机制在遇到版本冲突时,可能导致某些子项目依赖被覆盖,或者需要存储多个版本。更牛B的是pnpm的存储结构,下载依赖时,他直接把依赖放在了全局统一的目录中(~/.pnpm-store)中,项目中使用该依赖的时候,直接用硬链接或者软连接指向全局存储并使用,当其他子项目再安装这个依赖的时候,回去检查全局目录有没有这个依赖,如果有,直接就指向这个依赖,连安装的时间都省了,还节省空间。hoist机制使npm和yarn能在特定的条件下合并共享依赖 ,而pnpm直接就在全局中存储依赖,只要版本一致,整个设备都不用安装第二次依赖,高下立判。

干掉幽灵依赖!

NPM 和 Yarn 的行为
  1. 安装依赖和声明的关联

    • 在使用 npm或yarn 安装依赖时:

      sql 复制代码
      npm install left-pad
      yarn add left-pad

      它们会将 left-pad添加到 package.json的 dependencies中。

    • 但是,如果你直接运行某些代码使用了未在 package.json 中声明的依赖(即这些依赖是通过其他包的间接依赖引入的),npmyarn 不会阻止你使用它们。这就导致了幽灵依赖问题。

  2. 问题根源

    • 因为 NPM 和 Yarn 使用的是扁平化依赖树 ,即所有的依赖都被放在 node_modules 的根目录下(只要版本不冲突)。这样,某个包的子依赖可能意外变得"可见",即使它没有明确声明为直接依赖。
PNPM 的行为
  1. 安装和声明严格对应

    • 使用 pnpm 安装包时,行为类似:

      sql 复制代码
      pnpm add left-pad

      它会将 left-pad 添加到 package.jsondependencies 中。

    • 但与 npmyarn 的不同之处在于,如果依赖未在 package.json 中声明,pnpm 会拒绝让代码访问它,即使它是通过间接依赖安装的。

  2. 严格隔离依赖

    • pnpm 的依赖树是嵌套结构,确保只有直接依赖出现在你的 node_modules 中的顶层,其他子依赖都放在它们各自的 node_modules 中。

    • 因此,如果你尝试导入一个未显式声明的依赖(即幽灵依赖),会出现如下错误:

      arduino 复制代码
      Error: Cannot find module 'left-pad'
  3. 总结对比

    • NPM 和 Yarn:即使包未声明为直接依赖,只要它通过间接方式安装,代码仍然可以访问(容易忽略声明)。
    • PNPM :严格要求 package.json 中声明依赖,未声明的包即使安装了也不可访问,完全避免幽灵依赖。

太多专业术语虽然严谨,却不好理解,卓卓贴心的安排了讲人话环节。

讲人话环节:npm和yarn是安装了包才会在package中声明,有时候会忽略声明,而pnpm是package.json中没有声明就不会安装包,package.json也是好起来了,农奴翻身把歌唱,从被决定的变成了决定的。

pnpm的hoist--脱裤子放屁?

通过上面的解释,我们可以知道,项目node_modules的依赖只是个硬链接,占据的空间本来就是可以忽略不计,那把他提升到父项目的node_modules是闹哪样?兼职和蒙古海军一样没用!。。。其实有点用,但不多

PNPM Hoist 的实际用途
  1. 解决旧代码或工具兼容性问题

    • 某些遗留项目或工具(如部分 Webpack 插件、Babel 配置)假定依赖可以从顶层直接访问。如果使用 PNPM 的默认嵌套结构,这些工具可能报错。
    • Hoist 可以在特定情况下恢复兼容性。
  2. 减少重复依赖

    • 在大规模项目中(尤其是 Monorepo),某些依赖可能被多个子项目反复安装。Hoist 可以将这些公共依赖提升到顶层,从而减少 node_modules 的深度和重复。
  3. 加快开发工具的运行速度

    • 某些开发工具(如 LSP、TS Server)在扫描 node_modules 时,面对深层次嵌套目录可能变慢。
    • Hoist 可以减少扫描的复杂性,提高运行效率。

人话环节

有些老依赖是根据npm项目和yarn项目的结构设计的,并且没有为pnpm特定再设计一个版本,而hoist可以使 pnpm项目结构更加'返祖',能获得更好的兼容性。

总结

pnpm简直完美,要我评价就是马中赤兔,人中卓卓!但是他还有一些不足之处,他毕竟太'年轻'了,自然就会有生态不如老包管理工具的问题存在,就像上面说的,明明很鸡肋的hoist却能在pnpm中被保留就是为了解决部分兼容性问题,但是以pnpm超强的性能,使用它的人肯定会越来越多,对生态系统支持的兼容性问题被解决只是时间问题。

相关推荐
m0_7482548812 分钟前
前端大屏自适应方案
开发语言·前端·javascript
小刘鸭!13 分钟前
notepad++快捷键-多行编辑中如何使所有行的光标都向后移动一个单词的长度(每行单词长度不一定一致)
前端·javascript·notepad++
power-辰南22 分钟前
大厂 Java 架构师面试题全解析
java·前端·面试
夜色呦24 分钟前
创新驱动医疗变革:SSM+Vue 医院预约挂号系统的设计与实践
前端·数据库·vue.js
来一碗刘肉面41 分钟前
antdv-<a-table>的使用
前端·javascript·anti-design-vue
桃园码工1 小时前
6_HTML5 SVG (2) --[HTML5 API 学习之旅]
前端·html5·svg
开心工作室_kaic1 小时前
springboot460实习生管理系统设计和实现(论文+源码)_kaic
运维·服务器·前端·数据库·vue.js
m0_748245171 小时前
前端下载文件的几种方式使用Blob下载文件
前端·状态模式
m0_748240911 小时前
常见问题QA的前端代码
前端
好青崧2 小时前
HTML 图像标签使用陷阱
前端·html