bibi7 / fe-daily-increase

一个记录开发日常和奇奇怪怪的点的repo
MIT License
5 stars 0 forks source link

npm install是如何安装一个依赖的? #36

Open bibi7 opened 5 years ago

bibi7 commented 5 years ago

第36个issue了。

--------------------正文-------------------- 一直挺好奇npm是如何下载依赖的(其实也不是很好奇。

参考了一下阮老师的相关东西,不过估计有些东西并不适用了,毕竟是16年写的。做个小总结吧(一搜相关标题出来的个人blog全是复制拷贝这篇,连个转字都不写,这些b真的气死我了

npm install怎么安装依赖?

下面我来演示一个0分且正常回答:

通过package.json来安装依赖。

一个起码不是零分的回答

先来搞清楚有个东西叫registry,有个网址叫https://registry.npmjs.org/${packageName}(原谅我用了模板字符串),填上不同的packageName就能得到该依赖的全部历史版本,具体可以搜查tarball关键字,返回的是压缩包地址。 如果后接版本号的话,可以直接返回该版本的相关信息(考虑到16年写的blog,重新试了试,并不能)

从 registry 下载压缩包之后,mac或者linux用户默认是放在/主目录/.npm下面,同时会解压出一个解压包,放在项目目录的/node_modules/中,可以做个test:

npm config get cache

image

那么从零开始一次npm install大概有如下步骤:

  1. 根据package.json,链接registry,得到该依赖的目前最新版本。
  2. 拿到最新的版本压缩包地址,下载并放在.npm目录下面。
  3. 解压缩,将解压出来的包放到项目的/node_modules/目录中。

如果有package-lock.json呢

看了看lock文件,有一个很明显的resolved字段,存储着对应的package压缩包地址,那么有这么一个合理的猜测

在下载依赖包的时候:

  1. 首先肯定是npm install。
  2. 其次,确定package.json中所需要的依赖版本,如果这个时候存在着package-lock.json,则有以下几步。 2.1 如果存在lock文件,并且该lock文件中存在着该依赖信息,那么会直接读取resolved字段获取依赖仓库地址。 2.2 如果不存在lock文件,那么会走刚才上面的步骤,从registry中获取依赖版本地址并且下载。如果依赖版本号包括^箭头,根据[major, minor, patch]的原则,会获取从左到右的第一位非零字符下最新包。比如^0.12.0会下载0.12.1,并不下载0.13.0
  3. 有了对应的依赖版本以后,npm会去检查对应的本地缓存,注意的是,这里的缓存指的不是./npm下面的文件,而是~/.npm/_cacache下面的二进制文件,有缓存的话会根据相应的索引,通过pacote把对应的二进制文件解压到/node_modules/下面。如果无依赖,则从仓库下载。
  4. 查找该模块的依赖,有的话回到第一步。

模块扁平化(dedupe)

如上我们得到了一颗依赖树,但是基于现代项目大量依赖的原因,依赖树大概率会存在依赖严重重复的问题,所以这一块的分界线主要是npm3以前和以后。 在确认了依赖树以后,一个项目可能会存在重复依赖。npm3前,会严格按照依赖树进行安装,所以往往会重复安装依赖。 比如有如下依赖树:

npm2

A和B同时依赖着C,区别只是版本不同,这个情况下,npm2最终打出来的真实依赖结构会遵循依赖树,即使他们的依赖版本相同

npm3

如上情况,在npm3中真正展现的依赖树结构如下:

可以看到1.0版本的C依赖被提升到了项目根结构作为一级依赖。是因为npm3以后,dedupe会尽可能的将所有模块理论上都放在第一层级,既然是尽可能了,那当然并不是全部的情况都适用,默认遵循三条规则:

  1. 在安装某个二级模块时,若发现第一层级还没有相同名称的模块,便把这第二层级的模块放在第一层级
  2. 在安装某个二级模块时,若发现第一层级有相同名称,相同版本的模块,便直接复用那个模块
  3. 在安装某个二级模块时,若发现第一层级有相同名称,但版本不同的模块,便只能嵌套在自身的父模块下方

所以回顾一下刚才的例子,如果A和B都依赖1.0版本的C的话,那么结构如下:

那么dedupe是不是一定就做到了完全复用模块呢?其实也不尽然:

在这种情况下,后者并不比前者高明到哪里去(华莱士叉腰),只能说还是解决了部分痛点吧。 image

令人头秃。。

参考: npm缓存浅析

mrtice commented 2 years ago

暴露姓名了小姐姐

mrtice commented 2 years ago

有个问题想请教下,https://registry.npmjs.org如果没有我要的依赖了我是否能忽略这个依赖