Yarn 安装机制
Yarn
是一个由 Facebook
、Google
、Exponent
和 Tilde
构建的新的 JavaScript
包管理器。它的出现是为了解决历史上 npm
的某些不足(比如 npm
对于依赖的完整性和一致性保障,以及 npm
安装速度过慢的问题等)。
安装理念 #
- 确定性:通过
yarn.lock
等机制,保证相同的依赖关系在任何机器和环境下,都可以以相同的方式被安装。 - 扁平化安装:将依赖包的不同版本,按照一定策略,归结为单个版本,以避免创建多个副本造成冗余(
npm
目前也有相同的优化)。 - 网络性能更好:
Yarn
采用了请求排队的理念,类似并发连接池,能够更好地利用网络资源;同时引入了更好的安装失败时的重试机制。 - 缓存机制:采用缓存机制,实现了离线模式(
npm
目前也有类似实现)。
yarn.lock
#
yarn.lock
结构整体和package-lock.json
结构类似。yarn.lock
并没有使用json
格式,而是采用了一种可读性较高的自定义标记格式。- **
yarn.lock
中子依赖的版本号不是固定版本 。**这说明yarn.lock
和package.json
配合才能确定node_modules
目录结构。
安装机制 #
检测包(
checking
):- 检测项目中是否存在
npm
相关文件,比如package-lock.json
等。如果有,则提示用户注意:这些文件的存在可能导致冲突。 - 这一步骤中,也会检查系统
OS
、CPU
等信息。
- 检测项目中是否存在
解析包(
resolving packages
):- 获取首层依赖:
dependencies
、devDependcies
、optionalDependencies
; - 遍历首层依赖以及递归查找每个依赖下嵌套依赖的版本信息,将解析过和正在解析的包用一个
Set
数据结构存储,保证统一版本范围内的包不会被重复解析:对于没有解析过的包,先尝试从yarn.lock
中获取版本信息,如若找不到则向Registry
发起请求获取满足版本范围内的已知最高的包信息; - 最终确定所有依赖的具体版本信息以及下载地址。
- 获取首层依赖:
获取包(
fetching packages
):- 检查缓存中是否当前依赖包,未命中缓存则下载包到缓存目录。
链接包(
linking packages
):- 解析
peerDependencies
,如果找不到符合peerDependencies
的包,则进行warning
提示; - 遵循扁平化原则,将项目中的依赖复制到项目
node_modules
下。
- 解析
构建包 (
building packages
):- 如果依赖包中存在二进制文件需要进行编译,则执行编译构建。
扁平化安装 #
早期 npm
(npm v2
)的设计非常简单,在安装依赖时将依赖放到项目的 node_modules
文件中;同时如果某个直接依赖 A 还依赖其他模块 B,作为间接依赖,模块 B 将会被下载到 A 的 node_modules
文件夹中,依此递归执行,最终形成了一颗巨大的依赖模块树,表现为:
- 项目依赖树层级非常深,不利于调试和排查问题;
- 依赖树的不同分支里,可能存在同样版本的相同依赖;
带来的问题是:
- 依赖重复安装,浪费较大空间资源,也使得安装速度过慢;
- 目录层级太深,导致文件路径太长,导致
windows
系统下删除node_modules
文件夹失败。
npm v3
之后,node_modules
的结构改成了扁平结构:
- 不管是直接依赖还是子依赖的依赖,优先放置在
node_modules
根目录; - 遇到相同依赖,判断已放置在依赖树中的依赖是否符合新依赖的版本范围,如果符合则跳过;不符合则在当前依赖的
node_modules
下放置该依赖。