likes
comments
collection
share

Node 第四章 Npm install原理

作者站长头像
站长
· 阅读数 3

在执行npm install 的时候发生了什么?

  1. 解析 package.json 文件
    • npm首先读取项目根目录下的 package.json 文件。
    • 解析该文件中的 dependenciesdevDependencies 对象,获取项目所需的所有依赖包及其版本号。
  2. 查询并解析依赖
    • 对于每个依赖,npm会查询npm注册中心,找到与package.json中指定的版本号相匹配的依赖版本。
    • 如果依赖还包含自己的依赖(子依赖),npm也会递归地进行查询和解析(需要注意的是,这里采用的是广度优先算法)。
  3. 检查本地缓存
    • npm会检查本地缓存中是否已经存在所需依赖的副本。
    • 如果本地缓存中已有所需版本的依赖,则直接从缓存中获取,而不会从npm注册中心下载。
  4. 下载依赖
    • 对于本地缓存中不存在的依赖,npm会从npm注册中心下载依赖包。
    • 下载的依赖包包含了依赖的代码和它自己的 package.json 文件。
  5. 安装依赖
    • 下载后的依赖包被解压到 node_modules 目录中。
    • 如果依赖包含子依赖,npm也会递归地安装这些子依赖。
  6. 执行生命周期脚本
    • 在安装过程中,npm会检查依赖的 package.json 文件中是否定义了生命周期脚本(如 preinstallinstallpostinstall 等)。
    • 如果有定义,npm会在相应的时机执行这些脚本。
  7. 生成或更新 package-lock.jsonnpm-shrinkwrap.json 文件
    • npm会生成或更新 package-lock.json 文件,以确保未来安装时能够得到相同版本的依赖。
    • 这有助于项目在不同环境和不同开发者之间保持依赖的一致性。
  8. 整理 node_modules 目录结构
    • 为了避免冗余和冲突,npm可能会对 node_modules 目录进行整理,优化依赖的存储结构。
    • 从npm v3开始,尽可能将依赖扁平化,以减少目录深度和重复的依赖副本。
  • node_modules文件夹内部文件在进行排序的时候,以.开头的放在最前面,例如启动命令的.bin文件夹,接着就是@开头的文件夹,最后则是普通的文件夹

真的能做到扁平化吗?

  • 扁平化只是理想的状态

Node 第四章 Npm install原理

  1. 如上图,Vue和React都用到同一个babel,且版本和名称都一样。所以babel会提到这个相同等级(一级模块)的一个依赖。
  2. 所以VueReact就能够复用同一个Babel模块,而不至于两个框架都要重新装一遍Babel,这样对于节省我们的电脑存储空间有好处。毕竟npm包是很大的,一不小心就占掉电脑好几G了
  3. 上面就是一种理想状态下的扁平化,扁平扁平就是同一层级下的意思(但需要名称、版本,均相同)

非理想状态

  • 当要复用的那个模块,需要的版本不同时。就像下面就不知道要复用C1.0还是C2.0
  • 像这种不理想情况下,就会单独安装,出现模块冗余的情况,给B继续搞一层node_modules,就无法节省空间了(非扁平化)

Node 第四章 Npm install原理

Node 第四章 Npm install原理

npm install 后续流程

Node 第四章 Npm install原理 该图的流程如下:

  1. 执行 npm install
    • 用户在终端或命令行界面中输入 npm install 命令并执行。
  2. 读取配置文件
    • npm 查看是否有配置文件(如 .npmrc),可能存在于项目目录(局部配置,先找这个)或用户主目录(全局配置,后找这个)中,如果都没找到就会去找npm内置的。
    • npm 根据这些配置文件来决定如何进行安装,例如代理服务器、镜像源等设置。
  3. 解析 package.jsonpackage-lock.json 文件
    • npm 读取并解析项目中的 package.jsonpackage-lock.json 文件来确定要安装的依赖包及版本。
  4. 检查 node_modules 目录和 package-lock.json
    • npm 检查 node_modules 目录和 package-lock.json 文件,确定是否已经存在满足版本要求的依赖包。
    • 如果 package-lock.jsonpackage.json版本不一致,并且 npm 版本是5.4(高版本)及以上,那么将会优先按照 package.json 中记录的版本来安装,并且更新lock文件。
    • package-lock.jsonpackage.json版本一致的话,就会遵循lock文件了
  5. 安装依赖
    • 根据解析出来的依赖信息,npm 开始安装依赖到 node_modules 目录中。
    • 如果在 node_modules 中检查缓存,已经存在符合版本要求的包,则不会重复安装,直接就解压了,没有就走另一条下载包资源=>检查完整性=>添加到缓存=>更新package.lock.json文件=>解压到node_modules的道路。
  6. 生命周期脚本执行
    • 在依赖安装的不同阶段,会执行相关的生命周期脚本,如 preinstallinstallpostinstall 等。
  7. 生成或更新 package-lock.json 文件
    • 在安装过程结束后,npm 会生成或更新 package-lock.json 文件。
    • 这保证了以后在其他环境中运行 npm install 能够安装到相同版本的包。

npmrc配置信息

registry=http://registry.npmjs.org/
# 定义npm的registry,即npm的包下载源

proxy=http://proxy.example.com:8080/
# 定义npm的代理服务器,用于访问网络

https-proxy=http://proxy.example.com:8080/
# 定义npm的https代理服务器,用于访问网络

strict-ssl=true
# 是否在SSL证书验证错误时退出

cafile=/path/to/cafile.pem
# 定义自定义CA证书文件的路径

user-agent=npm/{npm-version} node/{node-version} {platform}
# 自定义请求头中的User-Agent

save=true
# 安装包时是否自动保存到package.json的dependencies中

save-dev=true
# 安装包时是否自动保存到package.json的devDependencies中

save-exact=true
# 安装包时是否精确保存版本号

engine-strict=true
# 是否在安装时检查依赖的node和npm版本是否符合要求

scripts-prepend-node-path=true
# 是否在运行脚本时自动将node的路径添加到PATH环境变量中

package-lock.json 的作用

  • 这个东西不仅可以锁定版本记录依赖树详细信息,还有如下作用
  1. version 该参数指定了当前包的版本号
  2. resolved 该参数指定了当前包的下载地址
  3. integrity 用于验证包的完整性,是一串哈希值
  4. dev 该参数指定了当前包是一个开发依赖包(参数需要是true)
  5. bin 该参数指定了当前包中可执行文件的路径和名称,也就是说有bin就表示这里有可执行文件
  6. engines 该参数指定了当前包所依赖的Node.js版本范围

package-lock.json 帮我们做了缓存,他会通过 name + version + integrity 信息生成一个唯一的key,这个key能找到对应的index-v5 下的缓存记录 也就是npm cache 文件夹下的

  1. 通过npm config list在终端查找缓存文件在哪

Node 第四章 Npm install原理 Node 第四章 Npm install原理

2. 通过这个路径进行查找文件

Node 第四章 Npm install原理

  • index-v5是一个索引目录,记录content-v2的一个索引或者说是位置,也就是name + version + integrity的一个哈希值。如果lock锁文件内的这三者和index-v5能够对上,就会去content-v2找到你缓存的那个文件。
    • 其实就是把项目中name + version + integrity组成的哈希值的看成一个钥匙就够了,而content-v2则是一个宝箱,index-v5则是一个钥匙孔。他们之前的关系就非常清晰了
  • name + version + integrity 哈希值:这相当于是一个钥匙。在npm中,每个包都有一个唯一的名称(name)、版本号(version),以及一个完整性校验值(integrity),这个校验值通常是一个SHA值,用于确保包的内容没有被篡改。将这三者组合起来,就形成了一个能唯一标识和验证一个包的“钥匙”。
  • content-v2:这个目录可以被看作是一个宝箱。它存储了你电脑上缓存的npm包的实际内容。每个缓存的内容都通过一种散列算法(如SHA-512)生成了一个独特的哈希值。
  • index-v5:这个目录就像一个钥匙孔,或者说是一本索引册。它记录了缓存内容的索引信息,这些信息将包的名字、版本和完整性校验值映射到它们在 content-v2 宝箱中的具体位置。

当运行npm install时,如果package-lock.json中的包信息(即钥匙)与index-v5的索引信息(即钥匙孔)匹配,npm就知道它可以直接使用content-v2中对应的缓存内容(即宝箱里的宝藏),而无需重新下载相同的包。这种机制加快了安装过程,同时确保了安装的一致性和包的完整性。