Open bibi7 opened 5 years ago
第36个issue了。
--------------------正文-------------------- 一直挺好奇npm是如何下载依赖的(其实也不是很好奇。
参考了一下阮老师的相关东西,不过估计有些东西并不适用了,毕竟是16年写的。做个小总结吧(一搜相关标题出来的个人blog全是复制拷贝这篇,连个转字都不写,这些b真的气死我了
下面我来演示一个0分且正常回答:
通过package.json来安装依赖。
package.json
先来搞清楚有个东西叫registry,有个网址叫https://registry.npmjs.org/${packageName}(原谅我用了模板字符串),填上不同的packageName就能得到该依赖的全部历史版本,具体可以搜查tarball关键字,返回的是压缩包地址。 如果后接版本号的话,可以直接返回该版本的相关信息(考虑到16年写的blog,重新试了试,并不能)
registry
https://registry.npmjs.org/${packageName}
tarball
从 registry 下载压缩包之后,mac或者linux用户默认是放在/主目录/.npm下面,同时会解压出一个解压包,放在项目目录的/node_modules/中,可以做个test:
/主目录/.npm
/node_modules/
npm config get cache
那么从零开始一次npm install大概有如下步骤:
.npm
看了看lock文件,有一个很明显的resolved字段,存储着对应的package压缩包地址,那么有这么一个合理的猜测
resolved
在下载依赖包的时候:
package-lock.json
^
^0.12.0
0.12.1
0.13.0
~/.npm/_cacache
如上我们得到了一颗依赖树,但是基于现代项目大量依赖的原因,依赖树大概率会存在依赖严重重复的问题,所以这一块的分界线主要是npm3以前和以后。 在确认了依赖树以后,一个项目可能会存在重复依赖。npm3前,会严格按照依赖树进行安装,所以往往会重复安装依赖。 比如有如下依赖树:
A和B同时依赖着C,区别只是版本不同,这个情况下,npm2最终打出来的真实依赖结构会遵循依赖树,即使他们的依赖版本相同
如上情况,在npm3中真正展现的依赖树结构如下:
可以看到1.0版本的C依赖被提升到了项目根结构作为一级依赖。是因为npm3以后,dedupe会尽可能的将所有模块理论上都放在第一层级,既然是尽可能了,那当然并不是全部的情况都适用,默认遵循三条规则:
所以回顾一下刚才的例子,如果A和B都依赖1.0版本的C的话,那么结构如下:
那么dedupe是不是一定就做到了完全复用模块呢?其实也不尽然:
在这种情况下,后者并不比前者高明到哪里去(华莱士叉腰),只能说还是解决了部分痛点吧。
令人头秃。。
参考: npm缓存浅析
暴露姓名了小姐姐
有个问题想请教下,https://registry.npmjs.org如果没有我要的依赖了我是否能忽略这个依赖
第36个issue了。
--------------------正文-------------------- 一直挺好奇npm是如何下载依赖的(其实也不是很好奇。
参考了一下阮老师的相关东西,不过估计有些东西并不适用了,毕竟是16年写的。做个小总结吧(一搜相关标题出来的个人blog全是复制拷贝这篇,连个转字都不写,这些b真的气死我了
npm install怎么安装依赖?
下面我来演示一个0分且正常回答:
一个起码不是零分的回答
先来搞清楚有个东西叫
registry
,有个网址叫https://registry.npmjs.org/${packageName}
(原谅我用了模板字符串),填上不同的packageName就能得到该依赖的全部历史版本,具体可以搜查tarball
关键字,返回的是压缩包地址。 如果后接版本号的话,可以直接返回该版本的相关信息(考虑到16年写的blog,重新试了试,并不能)从 registry 下载压缩包之后,mac或者linux用户默认是放在
/主目录/.npm
下面,同时会解压出一个解压包,放在项目目录的/node_modules/
中,可以做个test:那么从零开始一次npm install大概有如下步骤:
package.json
,链接registry
,得到该依赖的目前最新版本。.npm
目录下面。/node_modules/
目录中。如果有package-lock.json呢
看了看lock文件,有一个很明显的
resolved
字段,存储着对应的package压缩包地址,那么有这么一个合理的猜测在下载依赖包的时候:
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
~/.npm/_cacache
下面的二进制文件,有缓存的话会根据相应的索引,通过pacote把对应的二进制文件解压到/node_modules/
下面。如果无依赖,则从仓库下载。模块扁平化(dedupe)
如上我们得到了一颗依赖树,但是基于现代项目大量依赖的原因,依赖树大概率会存在依赖严重重复的问题,所以这一块的分界线主要是npm3以前和以后。 在确认了依赖树以后,一个项目可能会存在重复依赖。npm3前,会严格按照依赖树进行安装,所以往往会重复安装依赖。 比如有如下依赖树:
npm2
A和B同时依赖着C,区别只是版本不同,这个情况下,npm2最终打出来的真实依赖结构会遵循依赖树,即使他们的依赖版本相同
npm3
如上情况,在npm3中真正展现的依赖树结构如下:
可以看到1.0版本的C依赖被提升到了项目根结构作为一级依赖。是因为npm3以后,dedupe会尽可能的将所有模块理论上都放在第一层级,既然是尽可能了,那当然并不是全部的情况都适用,默认遵循三条规则:
所以回顾一下刚才的例子,如果A和B都依赖1.0版本的C的话,那么结构如下:
那么dedupe是不是一定就做到了完全复用模块呢?其实也不尽然:
在这种情况下,后者并不比前者高明到哪里去(华莱士叉腰),只能说还是解决了部分痛点吧。
令人头秃。。
参考: npm缓存浅析