包管理工具
这里会对市场上使用最多的包管理工具 yarn/ npm 以及新秀 pnpm 做一个横向分析
1. 前言
在做分析以及学习之前,最好可以读下 pnpm 官网。可以理解下 pnpm 的核心宗旨
- 当使用 npm 或 Yarn 时,如果你有 100 个项目,并且所有项目都有一个相同的依赖包,那么, 你在硬盘上就需要保存 100 份该相同依赖包的副本。然而,如果是使用 pnpm,依赖包将被 存放在一个统一的位置,因此:
- 如果你对同一依赖包需要使用不同的版本,则仅有 版本之间不同的文件会被存储起来。例如,如果某个依赖包包含 100 个文件,其发布了一个新 版本,并且新版本中只有一个文件有修改,则 pnpm update 只需要添加一个 新文件到存储中,而不会因为一个文件的修改而保存依赖包的 所有文件。
- 所有文件都保存在硬盘上的统一的位置。当安装软件包时, 其包含的所有文件都会硬链接自此位置,而不会占用 额外的硬盘空间。这让你可以在项目之间方便地共享相同版本的 依赖包。
2. 理想中包依赖
- 理想中的依赖可以是上述这种。我们的
XXX
项目依赖于多个插件,插件统一在文件夹node_moudles
下进行管理 - 而他们各自的依赖中,又依赖于别的插件。也是在各自
node_moudles
中进行管理 - 这样相互依赖 其实就构成了一颗多叉树。如下图
问题
- 虽然上述的依赖结构是清晰易懂的,但是同时存在了很多的问题:
- 依赖层次过深
- 依赖的子包的重复性很高。无法实现复用,占用了多余的磁盘空间
- 如果一个包被多个项目依赖的话,就会在本地磁盘中出现多份
- 那么不断的新的工具产生的话,就是为了解决上述的问题
3. 进化史
- 这里会大致的说一下包管理工具的发展史。因为肯定是新工具的出现解决了一些老的问题
- 同时也是会拿最新版的包管理工具做对比
npm(先)
- 不确定性
- 在 npm v5 版本之前是没有
package.json
文件的。是无法锁定版本的。这样就造成了很可能一个团队中依赖的项目的版本不同,这样会造成安全隐患
- 在 npm v5 版本之前是没有
- 下载速度缓慢
- 这个需要结合
yarn
进行分析
- 这个需要结合
幽灵依赖
- 在 npm v3 之后为了修改解决依赖过深以及无法利用的问题,改为扁平化管理。
- 但是这样会造成一个问题不是在
package.json
中写的依赖,也会被提升到node_moudles
的最顶端。 - 而我们可以在项目中直接依赖他们。但是他们会在某一时刻随别的包一起被卸载,而我们却不得知
依赖分身
- 上述存在两个一模一样的包
D@2.0
其实就是依赖分身 - 其实在实例项目中 只需要依赖包
A/ B/ C
. 但是 A => D@1.0/ B => D@2.0/ C => D@2.0 - 因为包 A 优先被下载,所以子依赖
D@1.0
被提升到顶端了
- 上述存在两个一模一样的包
- 不能充分利用缓存
- 如果本地磁盘中存在 100 个项目,每个项目都依赖一个相同版本的
rollup
那么会在本地有 100 个相同版本的依赖。也是对本地磁盘的一种浪费
- 如果本地磁盘中存在 100 个项目,每个项目都依赖一个相同版本的
yarn(中)
为了解决 npm 的问题,
yarn
应运而生了。
- yarn 引入了 yarn.lock 的概念,能更好的锁定版本,顺便解决了 npm 的问题
- 同样 yarn 在下载机制中引入了线程池的概念,加载速度提高
- 但是幽灵依赖/ 依赖分身/ 不能充分利用缓存 依旧没有解决
pnpm(后)
在 pnpm 中 就很好的解决了 npm/ yarn 遗留下来的问题。但是也不是一点问题没有
- 前奏知识
- 硬链接的作用:是允许一个文件拥有多个有效路径名,这样用户就可以建立硬链接到重要文件,以防止“误删”的功能。其原因如上所述,因为对应该目录的索引节点有一个以上的链接。只删除一个链接并不影响索引节点本身和其它的链接,只有当最后一个链接被删除后,文件的数据块及目录的链接才会被释放。也就是说,文件真正删除的条件是与之相关的所有硬链接文件均被删除
- 软连接的作用:有点像是 window 中的快捷方式,它本身也是一个文件,只不过保存的是它指向的文件的全路径,访问时将通过它访问所指向的文件路径以打开指定文件,所以当删除源文件时,打开它将报错指示无相关路径
-
其实就如上图所言,pnpm 中充分利用了硬链接/ 软连接的操作。那么是如何解决问题的呢
-
首先 pnpm 同样有 package-pnpm.lock 存在,可以锁定版本
-
其不是依靠扁平化策略来管理的的,所以所谓的
依赖分身
以及幽灵依赖
问题不存在 -
那如何进行操作的呢?
- 在下载依赖的时候,会在盘符中建立一个
.store
文件夹用来做同一个的依赖仓库 - 项目中所有的需要用到的依赖都是通过硬链接的作用,连接到项目的 node_modules 下面的
- 如果项目中用到相同版本的依赖是通过软连接进行管理的
- 这样就充分解决了依赖包重复性的问题(npm/ yarn 为了解决重复性的问题 才会有扁平化处理的)
- 在下载依赖的时候,会在盘符中建立一个
-
但是这样就很完美了吗???其实并不是的
- 在 pnpm 中严重依赖硬链接/ 软连接。如果你的系统不支持这个操作也是不行的
- 但是 pnpm 同样给了策略了。可以在
.npmrc
中添加配置 就跟 npm/ yarn 保持一致了