Node 第四章 Npm install原理

在执行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文件夹,接着就是@开头的文件夹,最后则是普通的文件夹

真的能做到扁平化吗?

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

非理想状态

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

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配置信息

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在终端查找缓存文件在哪

  1. 通过这个路径进行查找文件
  • 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中对应的缓存内容(即宝箱里的宝藏),而无需重新下载相同的包。这种机制加快了安装过程,同时确保了安装的一致性和包的完整性。

相关推荐
风清云淡_A6 分钟前
【es6】原生js在页面上画矩形层级等问题的优化(二)
前端·es6
vvvae123422 分钟前
JavaScript 前端开发操作指南
开发语言·javascript·ecmascript
前端Hardy1 小时前
HTML & CSS 魔法秀:打造翻转卡片登录注册页面
javascript·css·html
努力挣钱的小鑫1 小时前
【Vue3】弹窗添加鼠标hover上边缘左、下的的拉伸宽度高度操作
javascript·vue·计算机外设
hvinsion1 小时前
HTML 霓虹灯开关效果
前端·html
顾平安1 小时前
JS 预编译代码实例分析
前端·js
雾恋2 小时前
leaferjs元素的基本使用
前端·javascript·vue.js
好奇的菜鸟2 小时前
Vue.js 实现用户注册功能
前端·javascript·vue.js
是程序喵呀2 小时前
vue安装步骤
前端·javascript·vue.js
前端Hardy2 小时前
HTML 中 a 标签跳转问题总结:从框架页面跳转的困境与突破
前端·javascript·html