• Ukieweb

    佳的博客

    曾梦想仗剑天涯,后来工作忙没去。

npm & yarn 包管理机制

1. npm 

npm 会优先依赖包安装到项目目录。 

这样做的好处是使不同项目的依赖独立开来缺点也比较明显,如果我们两个项目 repo_a 和 repo_b 都有一个相同的依赖 pkg_c,那么这个公共依赖将在两个项目各被安装一次。也就是说,同一个依赖可能在我们的电脑上多次安装

npm install 

npm-install.png

上图是 npm 安装依赖大致的过程,其中这样几个步骤需要关注:

检查配置

包括项目级用户级全局级内置的 .npmrc 文件。

确定依赖版本,构建依赖树

确定项目依赖版本两个来源,一是 package.json 文件,一是 lockfile 文件,两个确认版本、构建依赖树的来源,互不可少、相辅相成。

如果 package-lock.json 文件存在且符合 package.json 声明的的情况下,直接读取;否则重新确认依赖的版本。

下载包资源

下载前先确认本地是否存在匹配的缓存版本,如果有就直接使用缓存文件,如果没有就下载添加到缓存,然后将包按依赖解压到 node_modules 目录

生成 lockfile 文件

2. yarn 

yarn 作为区别于 npm 的依赖管理工具,诞生之初就是为了解决历史上 npm 的某些不足,比如 npm 缺乏对于依赖的完整性一致性保障,以及 npm 安装速度过慢的问题等,yarn 提出的安装理念很好的解决了当时 npm 的依赖管理问题:

yarn 特性

确定性

通过 yarn.lock 等机制,保证了确定性,这里的确定性包括但不限于明确的依赖版本、明确的依赖安装结构等。即在任何机器和环境下,都可以以相同的方式被安装

模块扁平化安装

依赖包的不同版本,按照一定策略,归结为单个版本,以避免创建多个副本造成冗余。(npm 也有相同的优化)

更好的网络性能

Yarn 采用了请求排队的理念,类似并发连接池,能够更好地利用网络资源;同时引入了更好的安装失败时的重试机制。(npm 较早的版本是顺序下载,当第一个包完全下载完成后,才会将下载控制权交给下一个包)

引入缓存机制,实现离线策略。(npm 也有类似的优化)

yarn install

以下是在 yarn 安装依赖时的步骤:

image.png

检测包

这一步主要检测项目中是否存在npm相关的文件,如 package-lock.json 如果存在,则给出提示,可能会引发冲突,同时在这一步会去解析OS、CPU等相关信息。

解析包 resolving packages

这一步重点就是分析依赖,得到一个依赖关系图确定版本信息等。

首先获取项目 package.json 中声明的首层依赖,包括 dependencies, devDependencies, optionalDependencies 声明的依赖。

接着采用遍历首层依赖的方式获取依赖包版本信息,以及递归查找每个依赖下嵌套依赖的版本信息,并将解析过和正在解析的包用一个 Set 数据结构来存储,这样就能保证同一个版本范围内的包不会被重复解析。

对于没有解析过的包,首次尝试从 yarn.lock获取到版本信息,并标记为已解析;如果在 yarn.lock 中没有找到包,则向 Registry 发起请求获取满足版本范围的已知最高版本的包信息,获取后将当前包标记为已解析。

总之,在经过复杂的解析算法后,我们就确定了所有依赖的具体版本信息以及下载地址

获取包(fetching packages) 

这一步主要是到缓存中找到具体的资源。首先会尝试在缓存中查找依赖包,如果没有命中缓存,则将依赖包下载到缓存中。

对于没有命中缓存的包,Yarn 会维护一个 fetch 队列,按照规则进行网络请求。这里也是 yarn 诞生之初解决 npm v3 安装缓慢问题的优化点,支持并行下载

如何判断有没有命中缓存?

判断系统中存在符合 "cachefolder+slug+node_modules+pkg.name" 规则的路径,如果存在则判断为命中缓存,否则就会重新下载。

链接包(linking dependencies

 这一步主要是将缓存中的依赖,复制到项目目录下,同时遵循扁平化原则

在复制依赖前,Yarn 会先解析 peerDependencies,如果找不到符合 peerDependencies 声明的依赖版本,则进行 warning 提示(这并不会影响命令执行),并最终拷贝依赖到项目中

构建包(building fresh package)

 如果依赖包中存在二进制包需要进行编译,会在这一步进行。


0
0
下一篇:npm 和 yarn 的缓存 相关命令

0 条评论

老佳啊

85后,大专学历,中原人士,家里没矿。

由于年轻时长的比较帅气,导致在别人眼里,我一直不谈恋爱的原因是清高,实则是自己的小自卑。最大的人生目标就是找一个相知相爱相容的人,共度余生。

和人相处时如果能感受到真诚,会非常注重彼此的关系,对别人没有什么心机,即使有利益冲突,一般也会以和为贵,因为在这个世界上,物质的东西,从来不会吸引到我。

特别迷恋那些大山大水,如果现在还能隐居,可能早就去了。对那些宏伟的有底蕴的人文景观比较不感冒。

从事于IT行业,却一直对厨房念念不忘,由于身材魁梧,总觉得自己上辈子是个将军,可惜这辈子没当兵,也不会打架。