早期的npm

其实在最早期的npm版本(npm v2),npm的设计可以说是非常的简单,在安装依赖的时候会将依赖放到 node_modules文件中; 同时,如果某个直接依赖A依赖于其他的依赖包B,那么依赖B会作为间接依赖,安装到依赖A的文件夹node_modules中,然后可能多个包之间也会有出现同样的依赖递归的,如果项目一旦过大,那么必然会形成一棵巨大的依赖树,依赖包会出现重复,形成”嵌套地狱“。

如何理解“嵌套地狱”呢?

1、首先,项目的依赖树的层级过于深,如果有问题不利于排查和调试
2、在依赖的分支中,可能会出现同样版本的相互依赖的问题

”嵌套地狱“带来的后果:

1、首先,会使得安装的结果占据了大量的空间资源,造成了资源的浪费
2、同时,因为安装的依赖重复,会造成在安装依赖时,安装时间过长
3、甚至是,因为目录层级过深,导致文件路径过长,会在windows系统下删除node_modules文件,出现删除不掉的情况

yarn的出现

yarn 是一个由Facebook、Google、Exponent和Tilde构建的新的JavaScript包管理器。它的出现是为了解决历史上npm的某些不足(比如npm对于依赖的完整性和一致性的保证,以及npm安装过程中速度很慢的问题)

当npm还处于v3时期的时候,一个叫yarn的包管理工具横空出世.在2016年, npm还没有package-lock.json文件,安装的时候速度很慢,稳定性很差,yarn的出现很好的解决了一下的一些问题:

· 确定性:通过yarn.lock等机制,即使是不同的安装顺序,相同的依赖关系在任何的环境和容器中,都可以以相同的方式安装。

· 采用模块扁平化的安装模式:将不同版本的依赖包,按照一定的策略,归结为单个版本;以避免创建多个版本造成工程的冗余(目前版本的npm也有相同的优化)

· 网络性能更好:yarn采用了请求排队的理念,类似于并发池连接,能够更好的利用网络资源;同时也引入了一种安装失败的重试机制

· 采用缓存机制,实现了离线模式:目前的npm也有类似的实现。

相对于npm,yarn另一个显著的区别就是yarn.lock的子依赖的版本不是固定的版本。

yarn的安装机制

yarn的安装大致分为5个步骤:

yarn和npm区别 npm和yarn会冲突吗_yarn和npm区别


检测(checking) —> 解析包(Resolving Packages) —> 获取包(Fetching) —> 链接包(Linking Packages) —> 构建包(Building Packages)

检测包:
这一步的主要目的就是检测我们项目中是否存在npm相关的文件,比如package-lock.json等;如果有,就会有相关的提示用户注意:这些文件可能存在冲突。在这一步骤中,也会检测系统OS,CPU等信息。

解析包:
这一步会解析依赖树中的每一个包的信息:
首先,获取到首层依赖:也就是我们当前所处的项目中的package.json定义的dependencies、devDependencies、optionalDependencies的内容。
紧接着会采用遍历首层依赖的方式来获取包的依赖信息,以及递归查找每个依赖下嵌套依赖的版本信息,并将解析过的包和正在进行解析包呢用Set数据结构进行存储,这样就可以保证同一版本范围内的包不会进行重复的解析。

经过解析包这一步之后,可以确定解析包的具体版本信息和包的下载地址。

获取包:

这一步首先会检查缓存中是否有当前依赖的包,同时将缓存中不存在的包下载到缓存的目录中。但是如何去判断缓存中是否有当前的依赖包呢?
在Yarn中会根据cacheFolder+slug+node_modules+pkg.name生成一个路径;判断系统中是否存在该path,如果存在证明已经有缓存,不用重新下载。这个path也就是依赖包缓存的具体路径。

链接包:

上一步已经把依赖放到了缓存目录,接下来就需要把项目中的依赖复制到node_modules目录下,同时需要遵循扁平化的原则。在复制依赖之前,yarn会先解析peerDepdencies,如果找不到符合要求的,会有warning提示,并最终拷贝依赖到项目中。