【NodeJS】运行 npm install 指令后到底做了什么?

89 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情

背景:在运行一个新项目之前,我们常常需要使用指令 “npm install” 来下载依赖包,然后会在当前目录下生成一个 node_modules 文件夹。但是实际上它的底层是怎么实现的呢?今天我们就来一起探究一下!

1. NPM 简介

  • 1.全称 Node Package Manager,也就是 Node 包管理器;
  • 2.目前已经不仅仅是 Node 包管理器了,在前端项目中我们也在使用它来管理依赖的包,比如 express、koa、react、react-dom、axios、babel、webpack 等;
  • 3.npm 管理的包存放在 regsitry 仓库中,我们发布的包就是发布到了 registry 上,安装一个包也是从 registry 上面下载的包;
  • 4.官网:www.npmjs.com/
  • 5.其他常见的包管理工具:yarn。yarn 是为了弥补 npm 的一些缺陷而出现的,比如安装依赖速度很慢、版本依赖混乱等。但从 npm5 版本开始,做了很多的升级和改进来弥补这些问题。

2. 项目配置文件

在 Node 环境下,每个项目文件的根目录下都有一个 package.json 文件,这个配置文件会记录着项目的名称、版本号、项目描述等,也会记录着项目所依赖的其他库的信息和依赖库的版本号。

  • 可以使用 npm init 或者 npm init -y 来生成 package.json 文件

下面是某个项目中 package.json 文件的部分截图:

image.png

2.1 版本管理规范:semver

我们会发现依赖的版本出现 “^0.19.2” 或者 “~0.19.2”,这是什么意思呢?

  1. npm的包通常需要遵从 semver 版本规范:
  1. semver版本规范是X.Y.Z:
  • X 主版本号(major):当你做了不兼容的 API 修改(可能不兼容之前的版本);
  • Y 次版本号(minor):当你做了向下兼容的功能性新增(新功能增加,但是兼容之前的版本);
  • Z 修订号(patch):当你做了向下兼容的问题修正(没有新功能,修复了之前版本的bug)。
  1. ^ 和 ~ 的区别:
  • ^x.y.z:表示 x 是保持不变的,y 和 z 永远安装最新的版本;
  • ~x.y.z:表示 x 和 y 保持不变的,z 永远安装最新的版本。

2.2 拓展:package.json 中的常见属性

  • name:项目的名称
  • version:当前项目的版本号
  • private:记录当前的项目是否是私有的,值为 true 时,npm 是不能发布它的,这是防止私有项目或模块发布出去的方式
  • main:设置程序的入口
  • scripts:用于配置脚本命名,以键值对的方式存在,配置后我们可以通过 npm run + 命令的 key 来执行这个命令(对于常用的 start、test、stop、restart 可以省略掉 run 直接通过 npm start 等方式运行)
  • dependencies:指定无论开发环境还是生成环境都需要依赖的包
  • devDependencies:开发环境需要使用的依赖

3. npm install 原理

image.png

流程分析:

    1. 首先会检测是否有 package-lock.json 文件;
    1. 情况一:没有
    • (1)分析依赖关系,项目中可能会依赖其他的包,并且多个包之间会产生相同的依赖关系;
    • (2)从 registry 仓库中下载压缩包(如果设置了镜像,则会从镜像服务器中下载压缩包);
    • (3)获取到压缩包后会对压缩包进行缓存(从 npm5 开始);
    • (4)将压缩包解压到项目的 node_module 文件夹中。
    1. 情况二:有
    • (1)检查 package.lock.json 中包的版本是否和 package.json 中的一致(按照 semver 版本规范检测);
    • (2)如果不一致则会重新构建依赖关系,直接会走顶层的流程;
    • (3)如果一致,会去优先查找缓存;
    • (4)没有找到,会从 registry 仓库下载,直接走顶层流程;
    • (5)查找到,会获取缓存中的压缩文件,并且将压缩文件解压到node_modules文件夹中。