一、npm
npm的全称Node Package Manager,也就是Node包管理器。它现在不仅仅作为包管理工具,在前端项目中我们经常使用npm来管理我们的项目依赖。
如何下载npm?
npm属于node的一个管理工具,所以只要安装了node,npm就自动被安装了。 node管理工具:nodejs.org/en/ 安装Node的过程会自动安装npm工具; npm的官网:www.npmjs.org/ 可以通过官网查看npm的一系列知识。
npm存放的包放在哪里?
npm的包实际上是存放在registry里面中的,我们自己发布的包也会保存到registry当中,当我们通过npm安装某个包的时候,其实npm是从registry中下载的。
1.1 npm版本的缺陷
可以看到每个依赖版本前面都有个"^"符号,有必要解释下这个版本的概念。
当x.y.z的情况下:表示是一个明确的版本号
当^x.y.z的情况下:表示是x版本保持不变,y和z永远是最新的。
当~x.y.z的情况下:表示的是x和y是保持不变的,z永远是最新的。
如图所示,css-loader:^6.7.1,这个字符告诉npm,安装主版本等于6的任意一个版本即可。所以如果我现在运行npm进行安装,npm将安装css-loader的主版本为6的最新版,可能是css-loader@6.8.5。
理论上新版本是向下兼容的,安装最新版是不会有什么问题的,应该能正常运行。
但是,另一方面,即使不同的开发人员使用了相同的package.json文件,在他们自己的机器上也可能会安装同一个库的不同种版本,这样就会存在潜在的难以调试的错误和“在我的电脑上…”的情形。
因此npm中的package.json中的依赖无法保持版本一致的缺陷,并且npm也依赖很多的库,这会导致嵌套依赖关系,并增加无法匹配相应版本的几率。
1.2 npm依赖结构的缺陷
在npm3以前,假如有一个项目依赖了A模块,A模块又依赖了B模块、B模块又依赖了C模块,那么他们所构成的依赖树结构如下图所示:
这个结构会很长很长,这对于基于Unix的操作系统来说只不过是一个小烦恼,但对于“windows”来说却是个破坏性的东西,因为有很多程序无法处理超过260个字符的文件路径名。
而npm3以后意识到该问题,npm则采取扁平化的方式的依赖树的方式去解决这个问题,如图所示
这样一个从原来很长的"nodeModules/moduesA/moudesB/moduesC"为"nodeModules/modulesC",这种方法的缺点是:npm必须首先遍历所有的项目依赖关系,然后再决定如何生成扁平的node_modules目录结构。npm必须为所有使用到的模块构建一个完整的依赖关系树,这是一个耗时的操作,因此npm安装依赖往往是很慢的。
1.3npm安装依赖
假如我们通过npm安装axios和elementui,npm要先等到elementui安装完以后,才会执行安装axios的操作,就像我们在js中使用async await使得某个异步函数变为同步,只有该异步函数有了结果才去执行后面的操作。
二、yarn
任何一个新技术的出现,都是为了解决上个技术存在的痛点。
yarn是一种新的hadoop资源管理器,是一个通用资源管理系统,可为上层应用系统提供统一的资源管理和调度。
yarn的基本思想是将JobTracker的两个主要功能资源管理和作业调度/监控分离,主要方法是创建一个全局的ResourceManager和若干个针对应用程序的ApplicationMaster。主要优点是大大减小了 JobTracker的资源消耗,并且让监测每一个 Job 子任务 (tasks) 状态的程序分布式化了,更安全、更优美。
2.1yarn版本的问题
yarn 解决了npm版本不确定性问题,yarn默认有一个 yarn.lock 文件锁定版本,它能保证"package.json"依赖安装的版本和实际的版本是一致,保持环境统一,不会出现像npm一样出现版本混乱的问题。
2.1yarn安装依赖
yarn的安装依赖是异步的,例如同时安装axios和elementui,yarn不会阻塞下载,会同时下载axios和elementui,因此不会因为某个依赖安装太费时间而导致后面的依赖一直处于等待下载的状态。
2.1yarn离线缓存
当yarn安装重复的依赖时,yarn会从本地获取,但是yarn提供了离线模式,yarn会从缓存中下载依赖,而npm虽然是本地获取,但它依旧会从网络下载。
三、pnpm
pnpm全称:performant npm ,意味“高性能的npm”。pnpm由npm/yarn衍生而来,解决了npm/yarn内部潜在的bug,极大的优化了性能,扩展了使用场景。被誉为“最先进的包管理工具”
我想指出的是,pnpm运行起来非常的快,甚至超过了npm和yarn。
为什么这么快呢? 因为它采用了一种巧妙的方法,利用硬链接和符号链接来避免复制所有本地缓存源文件,这是yarn的最大的性能弱点之一。
3.1硬链接和软连接
硬链接
在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索引节点号(Inode Index),在 Linux 中,允许多个文件名指向同一索引节点,一般这种连接就是硬链接。
硬链接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬链接到重要文件,以防止“误删”的功能。其原因如上所述,因为对应该目录的索引节点有一个以上的链接。只删除一个链接并不影响索引节点本身和其它的链接,只有当最后一个链接被删除后,文件的数据块及目录的链接才会被释放。也就是说,文件真正删除的条件是与之相关的所有硬链接文件均被删除。
软连接
准确来说叫符号链接(symbolic link),一般又叫软链接(soft link)。与硬链接共用一个inode不同,软链接会创建新的inode,并指向源文件。可以理解软链接就是windows系统中的桌面快捷方式。
3.2pnpm做了什么
当使用 npm 或 Yarn 时,如果你有100个项目使用了某个依赖(dependency),就会有100份该依赖的副本保存在硬盘上。而在使用 pnpm 时,依赖会被存储在内容可寻址的存储中,所以: 如果你用到了某依赖项的不同版本,那么只会将有差异的文件添加到仓库。 例如,如果某个包有100个文件,而它的新版本只改变了其中1个文件。那么 pnpm update 时只会向存储中心额外添加1个新文件,而不会因为仅仅一个文件的改变复制整新版本包的内容。 所有文件都会存储在硬盘上的某一位置。 当软件包被被安装时,包里的文件会 硬链接 到这一位置,而不会占用额外的磁盘空间。 这允许你跨项目地共享同一版本的依赖。因此,您在磁盘上节省了大量空间,这与项目和依赖项的数量成正比,并且安装速度要快得多!
3.3非扁平的目录
当使用 npm 或 Yarn Classic 安装依赖包时,所有软件包都将被提升到 node_modules 的 根目录下。其结果是,源码可以访问 本不属于当前项目所设定的依赖包。
默认情况下,pnpm 则是通过使用符号链接的方式仅将项目的直接依赖项添加到 node_modules 的根目录下。
四、总结
- npm仍然提供了一个非常有用的解决方案,支持大量的测试用例。大多数开发人员使用原始npm客户端仍然可以做得很好。
- yarn的确定性安装,可以避免很多潜在的问题,相对安全。
- pnpm可能是一些测试用例的更好的选择。例如,它可以在运行大量集成测试并希望尽可能快地安装依赖关系的中小型团队中发挥作用。