npm、yarn与pnpm都是目前开发中常用的包管理工具,它们都提供了命令行工具,方便开发者对第三方包进行下载、安装、升级与删除,也为开发者发布与维护各自开发包提供快捷的操作方法。那么既生瑜何生亮,我们来一探究竟吧。
npm
npm 是 Node.js 自带的包管理工具,在npm 2.x版本里,包的目录结构是树状结构,各安装包node_modules是相互嵌套的, 结构如下所示:
node_modules
└─ a
├─ index.js
├─ package.json
└─ node_modules
└─ b
├─ index.js
└─ package.json
test 项目下将npm版本切换至2.x,执行安装 express 后 node_modules 结构如下图所示,
展开 express,可见其目录下也有 node_modules,展开 express 的node_modules,可见 express 的各个依赖中也有各自的node_modules。这种结构存在的问题是,若多个包之间有公共的依赖,这样嵌套将导致同样的依赖会复制多次,从而占据很多磁盘空间。除此之外,这样的嵌套在 windows 中可能还会出现超过路径长度限制的情况。
yarn
yarn 也是一个常用的包管理工具,yarn的出现就是为了解决npm多层嵌套的问题的。其在用法上和 npm 十分相似, npmjs 上的包,也会同步到 yarnpkg 。
那么yarn是如何解决npm上述问题的呢?
项目中重新使用 yarn init 初始化项目后,通过yarn再次安装express,安装成功后的项目node_modules目录展开如上图所示,从图中我们可以看到,不同于npm 2.x的node_modules的嵌套结构,yarn的node_modules目录下的依赖是铺平的,
node_modules
├─ a
| ├─ index.js
| └─ package.json
└─ b
├─ index.js
└─ package.json
相较于之前的嵌套结构,铺平式的依赖管理下,所有的依赖都被拍平到node_modules 目录下,不再存在深层次的嵌套关系。这样在安装新的包时,如果找到相同版本的包就不会重新安装,解决了部分相同依赖包重复安装的问题,同时也解决了安装依赖路径过长的问题。
npm升级到npm3.x之后也采用了类似的方案,将安装依赖铺平。但是,安装依赖铺平处理仍然存在一些问题,如扁平化算法复杂度较高,处理过程耗时,以及项目中存在可以非法访问未声明的依赖包的问题。
pnpm
那么pnpm的出现就是为了解决npm与yarn安装依赖铺平中的问题,通过结合软硬链接与新的依赖组织方式,不仅提高了包管理的效率,同时也解决了非法访问未经声明的依赖包的问题。通过pnpm初始化项目,并再次安装express包,项目下node_modules如下图所示:
上图可见,pnpm安装express后, 项目node_modules下仅有项目依赖包,与package声明中基本一致。但是展开目录下.pnpm,其结构如下:
图中可见项目安装的所有依赖都在.pnpm中铺平,并通过软连接的方式与关联文件建立联系。
pnpm通过软硬连接组合的方式,不仅解决了相同依赖多次重复的问题,也解决了yarn与npm 3.x中非法访问未经声明的依赖的问题,同时也提升了磁盘空间利用率,这些突出的优点使得pnpm得到越来越多开发者的青睐。