关于包管理器Npm、Yarn和Pnpm的一些总结

写在前面在Node.js生态系统中,包管理器是至关重要的组件之一,它们负责维护各种应用程序和库之间的依赖关系 。npm是Node.js的默认包管理器,它的初始版本是npm1,但是它很快就被npm2所取代 。
npm2关于npm2最初作为包管理管理,采用的是node_modules嵌套模式,即每个包都会有自己独立的node_modules,且会将各自依赖进行安装,依赖的依赖也会产生自己的node_modules,这样就产生了“嵌套依赖” 。
就像回调嵌套一样,容易陷入回调地狱,嵌套依赖也不例外 。
这种嵌套依赖的模式,虽然可以使依赖项的版本更加明确和稳定,但是在实际应用中也存在一些问题 。其中最大的问题是包的嵌套层级很深,这可能会导致安装和更新依赖项的时间变长,并增加包的大小 。此外,由于每个包都有自己的node_modules文件夹,这可能会导致文件系统中出现大量重复的依赖项,从而占用更多的磁盘空间 。
在实际操作中,当需要在特定的Node.js版本中使用npm2时,可以使用Node Version Manager (nvm)来管理多个Node.js版本 。例如,在切换到Node.js v4.0版本时,对应的npm版本是npm2.x 。

关于包管理器Npm、Yarn和Pnpm的一些总结

文章插图
为了更好地说明嵌套依赖的问题,我们可以通过安装koa来演示 。koa是一个基于Node.js的Web应用程序框架,它有许多依赖项,我们可以使用以下命令来安装koa:
npm install koa在安装koa时,npm会自动下载和安装所有必需的依赖项,并将它们安装到koa的node_modules文件夹中 。如果我们检查koa的node_modules文件夹,我们会发现它包含了大量的依赖项,这些依赖项中又包含了更多的依赖项,导致整个文件夹的嵌套层级变得很深 。
关于包管理器Npm、Yarn和Pnpm的一些总结

文章插图
对于多包之间会存在公共依赖,如果对于每个依赖都生成自己独立的node_modules,那么就会对相同包重复安装多次,这就会占据很大的磁盘空间 。且无限嵌套,也会超过windows的最大文件路径长度限制(265个字符) 。
嵌套依赖项的模式是npm2中的一个特性,虽然可以保证依赖项的版本稳定性和精确性,但是它可能会导致嵌套层级变得很深,并占用大量的磁盘空间 。
yarn我们想到,既然树形结构存在弊端,为什么不将依赖包在根node_modules进行扁平化处理,这不就解决了依赖嵌套、依赖重复和路径限制问题了?
此时新方式yarn就横空诞生 。
当使用yarn进行依赖管理时,我们可以看到所有依赖都会被安装在根目录下的node_modules文件夹中 。与npm2不同的是,yarn采用了扁平依赖项的模式,这意味着相同的依赖包只会被安装一次,并且不会存在多个嵌套的node_modules文件夹 。
使用yarn add koa进行安装,可以看到通过yarn进行管理的依赖全部平铺在根node_modules下,且没有重复依赖安装的问题 。
关于包管理器Npm、Yarn和Pnpm的一些总结

文章插图
但是,当某些依赖包存在多个版本时,yarn会将其中一个版本提升到根node_modules文件夹中,而其他依赖包则会继续维护自己的版本 。这可能会导致某些依赖包无法正常工作,因为它们可能需要使用特定版本的依赖包 。为了解决这个问题,yarn仍然需要使用嵌套的node_modules文件夹,以确保每个依赖包使用正确的版本 。
关于包管理器Npm、Yarn和Pnpm的一些总结

文章插图
值得注意的是,yarn采用的扁平依赖项模式具有许多优点,例如更快的安装速度,更少的磁盘空间占用和更少的依赖冲突问题 。此外,yarn还提供了一个lock文件,该文件记录了所有依赖项的确切版本和位置,以确保依赖项的版本稳定性和一致性 。
yarn的变与不变:
yarn采用了更加高效和可靠的依赖项管理方式,可以有效地避免依赖冲突和嵌套的问题 。但是,对于某些多版本依赖包,yarn仍然需要使用node_modules嵌套的方式来确保每个依赖包都使用正确的版本 。
npm3npm3在2015年发布时引入了一种新的依赖项安装算法,称为“扁平依赖项” 。其主要原理是通过将所有依赖项都放置在同一个目录下,并使用符号链接来实现依赖项的共享 。
在npm3中,所有依赖项都被直接安装到根目录下的node_modules中,而不是像npm2一样在每个依赖包中嵌套一个node_modules目录 。这种扁平化的结构可以减少依赖项的嵌套层级,从而降低了磁盘空间的占用和文件路径的长度 。在这种模式下,所有依赖项都被安装到顶级node_modules文件夹中,这样就避免了嵌套依赖项的问题 。这种模式虽然简单,但是它可能会导致依赖项的版本不稳定,从而可能会导致依赖冲突的问题 。


推荐阅读