pnpm: 是 performant npm 的缩写,直译过来就是 高性能的 npm。说明 pnpm 也是一个包管理工具。
那么既然有了 npm,为什么还需要 pnpm 呢?
记住一句话:新的技术出现都是为了解决旧技术的不足之处。
为什么需要 pnpm?
先来看看包管理工具的发展历程。
下面的安装依赖包演示都是以
axios和lodash为例
npm2
npm2 最开始的时候,安装的依赖包,在 node_modules 文件夹下形成的目录结构形式如下:
安装的包在 node_modules 就会形成一种嵌套的形式。
那么 npm2 这种形式的,会存在什么问题呢?
- 如果多个包存在相同的依赖,如果是嵌套的话,那么依赖就会复制很多次,那么占据的磁盘空间是比较大的。
- 致命问题是,windows 的文件路径最长是260多个字符,如果嵌套层级深之后,那么就会超过 windows 限制的最大长度。
当 npm 还没有解决这个问题的时候,yarn 就诞生了。
npm3、yarn
yarn 的解决方式,就是实现了 node_modules 文件夹依赖包的平铺。所有的依赖不再一层层嵌套了,而是全部在同一层,这样也就没有依赖重复多次的问题了,也就没有路径过长的问题了。
文件目录结构形式:
当然遇到了多个不同版本的相同包,还是会采用嵌套的方式。
npm 升级到 3 版本以后,也是采用了平铺的方式,跟 yarn 类似。
采用平铺的方式,节约了大量的磁盘内存空间,也解决了 npm2 所带来的问题,那么又会存在的问题呢?
- 相同的包,版本多后,也会存在浪费磁盘内存空间。
- 最大的问题是:幽灵依赖
何为幽灵依赖?
因为 node_modules 中包的处于平铺状态,那么就会存在一些特殊包并不是项目的依赖包,即没有在 package.json 中 dependencies 声明。但是在项目中,也可以使用这些特殊包(因为在 node_modules 可以查找到的)
那么就会存在一种情况:
该特殊包在项目中使用了,但是在依赖包升级后,该特殊包被删除(或者被其他包所代替),那么就会造成项目报错,找不到包的路径。
那么针对上面的一系列问题:pnpm就出现了。
pnpm 的全面理解
理解官网对 pnpm 的概念解释
概念:pnpm 是 快速的,节省磁盘空间的包管理工具。
两个关键词:快速的,节省磁盘空间。
先看看官网的解释:
根据上面的描述,大致想表达的意思:
- npm 和 yarn 创建项目的时候,都会在磁盘中保存一份 node_modules 的依赖包(如果存在大量的相同包,就会造成很大的磁盘浪费)。
- pnpm 则是对依赖包则是采用统一的位置管理(store),当创建项目的时候,相同包
link的形式链接,不同包则安装。这样既省磁盘又节约时间。
小结:
- 所有的依赖包放在统一位置,存在多个项目的时候,都是通过链接的形式指向的。
- 针对不同版本的依赖包,只会针对不同的版本的不同文件的存储,相同的文件还是在磁盘中保持一份。
知道了 pnpm 为什么速度快并且节约磁盘空间。那么就聊一聊 pnpm 以 link 的形式链接到统一位置(store)。
pnpm 的实现原理:理解硬链接和软链接
在上面已经提及到,安装的依赖包都会统一安装到磁盘的某一个位置,项目中的文件就是以链接(link) 的形式进行指向。那么这里的链接是指的什么呢?
软链接和硬链接是操作系统里面的知识。
反正作为小白的我,是肯定不知道的。在看网上看了几篇博文关于该方面的知识,自己总结了一下。
如果下面内容说的有误,请指出来,虚心求教。
概念解释
硬链接(英语: hard link) : 是电脑文件系统中的多个文件平等地共享同一个文件存储单元。
符号链接(软链接 soft link / symbolic link) : 是一类特殊的文件,其包含一条以绝对路径或者相对路径的形式指向其他文件或者目录的引用。
不用说了,我自己都感觉到了抽象。
inode 和 文件名
文件的物理数据是存储在磁盘中的,读取数据是通过文件系统(file system)来获取的。
操作系统是通过 inode 来识别文件,用户是通过文件名来识别文件。
比如:当用户打开一个文件的时候,文件系统(file system)实际上是先通过文件名查找到对应的 inode 号码,然后根据 inode 号码找到对应的 inode 信息,根据 inode 信息找到文件内容的所在数据块,最后读取数据呈现。
这里就是为了引出 inode 概念。
复制、硬链接、软链接的对比
操作系统中,在文件的扩展方式,有大致三种:复制 、 硬链接 和 软链接。
- 文件复制,在磁盘中新开一个内容空间,存储复制的物理数据,两个文件不相互关联。
copy file file_copy # windows
cp file file_copy # macos
- 文件硬链接,新建一个文件,但是指向的是同一个 inode,文件之间的读写,会相互影响。
mklink /H file_hard file # windows /H 硬链接 file_hard 硬链接文件 file 原文件
ln file file_hard # macos
3. 文件软链接,就相当于电脑中的快捷方法,点击快捷方式,真实点击的内容还是原来的文件
mklink file_soft file # windows mklink默认软链接 file_soft 软链接文件 file 原文件
ln -s file file_soft # macos
硬链接、软链接的实战
复制就不需要了吧,谁不会复制copy呢,哈哈哈。
硬链接
- 创建原文件 file.js
- 创建硬链接
mklink /H file_hard.js file.js
效果:
改变原文件之后,硬链接文件也会跟着改变,反之亦然。
软链接
- 创建原文件 file.js
- 创建硬链接
mklink file_soft.js file.js
符号链接,也就是软链接
到了这里,相信大家对硬链接和软链接有了一定的认识(如果还是没有懂得话,就需要大家下去自己努力学习一下,哈哈哈)。
pnpm 的使用
学习 pnpm 语法正式开始。
全局安装
npm install -g pnpm
常用的基本命令(与 npm 对比)
| npm | pnpm |
|---|---|
| npm install | pnpm install |
| npm install package | pnpm add package |
| npm uninstall package | pnpm reomve package |
| npm run cmd | pnpm cmd |
当然还有其他的命令,自己去官网上看看吧!
认识 pnpm 的 node_modules 文件夹
以第三方包 axios 、lodash 为例
pnpm add axios
pnpm add lodash
node_modules的目录截图
可以看出来,axios 和 lodash 都是软链接,.pnpm 才是真是存放包的文件夹。
这里解决了幽灵依赖的问题
点击打开 .pnpm 文件夹
可以找到 axios 和 lodash 的文件夹,但是还存在其他的文件,是什么意思呢?
这些文件都是 axios 或者 lodash 依赖的第三方包,统一存放在 .pnpm 下。
在点击 axios 文件,截图如下:
axios 也依赖三个包 follow-redirects、form-data 和 proxy-form-env ,并且这三个文件都是软链接的形式,链接到 .pnpm 文件下的文件(也就是硬链接文件,在 .pnpm 是可以寻找到三个包的对应文件)
小结:
- 项目中的 package.json 中的依赖包都是以软链接的形式存在 node_modules 文件下,没有多一个也没有少一个,这样就解决了幽灵依赖
- 真实的文件(或者说硬链接文件)都是存放在
.pnpm文件下 - node_modules 的目录结构不是平铺的,是嵌套的方式,但是它们的依赖包都是以链接的形式指向
.pnpm下的文件
pnpm 的存储位置 store 及释放
在上面已经知道,pnpm 安装的第三方依赖包都是放在一个统一位置(store), 那么该如何知道存放在哪里呢?
在 pnpm 7.0 以前,就是存在统一的位置下 (以Windows为例:C:/Users/xxxx/.pnpm-score)。
pnpm 7.0 以后,就是没有固定的统一位置。为什么呢?
原因:有些磁盘之间不能创建硬链接。比如:固态硬盘和机械硬盘
既然没有存放在统一的固定位置,那么该如何查看呢?
pnpm store path # 查看 pnpm 安装包的位置
当创建项目太多,store 也会保存很多的无用文件,也会占用很大的磁盘空间(虽然相对于npm还是很小的)。
所以就需要手动释放一下 store 中无用的文件
pnpm store prune # 释放 store 文件下的无用文件
建议:也不要太频繁的释放 store,因为当创建项目的时候,发现里面没有相应的包文件,就会去下载新的包文件,会花费大量的时间,这样就体现不出 pnpm 的优势了。
总结
pnpm 作为一项新的包管理工具,还是值得我们学习的。虽然可能在最近两年可能不会用,但是并不代表以后不会用。
俗话说,技多不压身嘛。
上面写的有误的地方,请大家提出来哟,虚心受教。
参考资料
coderwhy的教学视频