摘要:我们日常在下载第三方依赖的时候,都会用到一个命令npm install,那么你知道,在运行这个命令的时候都会发生什么吗?

本文分享自华为云社区《运行npm install命令的时候会发生什么?》,作者: gentle_zhou。

npm(node package manager),是随同Node.js一起安装的第三方包管理器;通过npm,我们可以安装、共享、分发代码,管理项目的依赖关系。

我们日常在下载第三方依赖的时候,都会用到一个命令npm install,然后依赖包就会被安装到node_modules目录下;但是我们在运行这个命令的时候都会发生什么呢?带着好奇心,我去调研学习了一番。

大致的流程是:npm install命令输入 > 检查node_modules目录下是否存在指定的依赖 > 如果已经存在则不必重新安装 > 若不存在,继续下面的步骤 > 向 registry(本地电脑的.npmrc文件里有对应的配置地址)查询模块压缩包的网址 > 下载压缩包,存放到根目录里的.npm目录里 > 解压压缩包到当前项目的node_modules目录中。

(上面的图片就显示了项目中依赖如果过多的尴尬:等待时间过长,下载下来依赖过多导致node_modules过大)

下面会介绍一下npm处理依赖的早前和当前的方式 以及 几种不同的install命令下载方式。

早期版本:递归

在npm早期版本里,npm处理依赖的方式很粗暴简单。它会严格按照根目录下package.json文件的结构以及各个子依赖包的package.json文件的结构,递归地把依赖安装到它们各自的node_modules目录里。这样如果是个小项目,只需要几个依赖且这些依赖不会依赖别的依赖,那么这样的树形结构就还算清晰明了(node_modules的结构与package.json里的结构一一对应且层级结构明显)。

但如果我们的项目是个大项目,里面的依赖非常多(导致嵌套层级非常深),且不同的层级可能会引用同一个依赖(导致重复冗余),就不是我们想要的情形了。

当前版本:扁平化

于是,为了解决以上递归管理依赖带来的问题,npm在 3.X版本里做了一次更新,引入了扁平化管理(dedupe)的方式。dedupe是dedeplicated的缩写,即duplicates were remove,把重复的移除。

扁平化管理的思路就是首先遍历package.json文件下dependencies和devDependencies字段里的依赖,作为依赖树的根节点;然后在每个根节点依赖下面都会有其依赖的依赖,作为其子节点;npm会开启多进程从每个根节点开始逐步往下寻找更深层次的节点。而package.json文件下dependencies和devDependencies字段里的依赖会被安装在node_modules根目录下。在遍历这些依赖的时候,如果发现有重复的依赖模块(重复:模块名相同且semantic version兼容;这里的兼容,是指语义化版本都会有一段版本允许范围,如果两个依赖的版本号是在这个范围交际里就说明是兼容;比如依赖X依赖于依赖Y@^1.0.0,而依赖Z依赖于依赖Y@^1.1.0,则Y@^1.1.0就是兼容版本),就直接将其丢弃。

但是如果仅仅这样,其实也有风险。在大项目中,很有可能会碰到依赖A依赖于依赖C-1.0版本,依赖B依赖于依赖C-2.0版本;而在执行npm install命令的时候,会按照package.json里面的依赖顺序依次解析,因此依赖C-1.0和依赖C-2.0的在文件里的放置顺序会导致Node_modules的依赖结构产生变化。而且为了让开发者可以使用最新的依赖包,package.json文件里通常只会锁定大版本(即文件里依赖如果是^1.1.0版本,npm就会去仓库中获取符合1.x.x形式的最新版本),因此某些依赖包小版本更新后,也会造成依赖结构的改变。所以,为了解决npm install命令导致的这种不确定问题,npm 5.x版本里还新增了package-lock.json文件。

package-lock.json文件可以保证每次执行npm install后生成的node_modules目录结构一定是完全相同的。下图就是package-lock.json中其中一个依赖的信息,有name-包名,version-包的版本号,dependencies-和node_modules中包结构一一对应的对象,resolved-包具体的安装来源,integrity-包的hash值,requires-对应子依赖的依赖:

注:并不是所有的子依赖都有dependencies这个属性,只有子依赖的依赖和当前已安装在根目录的Node_modules中的依赖起了冲突之后,才会有这个属性。

置于为何说package-lock.json 文件 和 node_modules 目录结构是一一对应的。还是举刚刚前面提及的那个依赖冲突导致依赖结构产生变化的例子,“依赖A依赖于依赖C-1.0版本,依赖B依赖于依赖C-2.0版本”,此时因为package-lock.json文件的存在,我们会把依赖C-1.0版本安装在依赖A的node_modules目录下(对应依赖A在package.json文件里的dependencies属性),依赖C-2.0版本安装在根目录下。这可以保障每次安装生成的依赖目录结构保持相同。

package-lock.json 文件还有个优点,就是它会缓存每个包的具体版本和下载链接,在后期再去install的时候,就不需要再去远程仓库进行查询操作了,减少了大量网络请求。

几种不同的install命令下载方式

  1. npm install xxx #(XXX是某依赖包)安装依赖模块至项目node_modules目录下,不会修改package.json文件里的内容
  2. npm install -g xxx #安装依赖模块到全局(而不是项目node_modules目录下),不会将该依赖模块写到package.json文件里的dependencies和devDependencies字段里
  3. npm install --save xxx #安装依赖模块到项目node_modules目录下,并将依赖写入到package.json文件里的dependencies字段中;该依赖是开发和生产环境里都需要的
  4. npm install --save-dev xxx #安装依赖模块到项目node_modules目录下,并将依赖写入到package.json文件里的devDependencies字段中

点击关注,第一时间了解华为云新鲜技术~

运行npm install命令的时候会发生什么?的更多相关文章

  1. 当运行npm install 命令的时候带上ignore-scripts,会发生什么?

    摘要:运行npm install 命令的时候带上ignore-scripts, 可以避免一个恶意包里的病毒. 本文分享自华为云社区<运行npm install 命令的时候带上--ignore-s ...

  2. npm install命令详解

    -S,–save 安装包信息将加到dependencies(生产阶段的依赖) npm install --save 或 npm install -S -D, –save-dev 安装包信息将加到dev ...

  3. 关于 npm install 命令

    使用 `npm install` 命令安装模块时 ,有以下几种形式: 安装模块到项目 node_modules 目录下,不会将模块依赖写入 dependencies 或 devDependencies ...

  4. vs2015 打开项目自动运行 npm install

    问题:VS2015(visual studio 2015) 打开项目自动运行  npm install 解决办法: 打开工具-选项-项目与解决方案--外部web工具   去掉npm勾选 还有如果文件g ...

  5. npm install命令对package-lock.json文件自动做了一些额外的更新

    今天我使用 npm 命令给项目安装file-saver,通过git却发现package-lock.json中除了file-saver组件之外的其他组件的记录也被改了 npm为何会自动做这些更改呢,又如 ...

  6. npm install 命令。默认会找到当前路径下的package.json。然后安装其中的依赖

    npm install 命令.默认会找到当前路径下的package.json.然后安装其中的依赖 By default, npm install will install all modules li ...

  7. IDEA -01 -忽略指定文件夹 -防止加载Vue-cli执行"npm install"命令后的项目时卡死

    问题描述 Vue的"npm install" 命令执行后,会生成一个很大的目录层次的"node_modules",文件十分繁多; idea加载这个项目下的文件夹 ...

  8. elasticsearch-head-master下运行npm install报npm WARN elasticsearch-head@0.0.0 license should be a valid SPDX license expression

    2个月没有启动es和es配套服务,今天运行时,发现如下问题: 运行npm install 出现npm WARN elasticsearch-head@0.0.0 license should be a ...

  9. Nodejs中npm install 命令的问题

    在使用nodejs的npm包管理工具中碰到过许多个坑,在网上查了很久才解决,现在加以总结. 两种安装方式(本地安装,全局安装) 1.全局安装(npm install -g moduleName/npm ...

随机推荐

  1. json知识点总结(一)--基础介绍

    前言 JSON是一种轻量化的数据编码方式它不依赖于编程语言是独立的文本格式.和xml相比JSON具有格式简洁,转译速度快的特点,因此现在被广泛使用.JSON的本质是字符串,采用了特定的分隔方式对字符串 ...

  2. Joplin开源笔记软件使用入门

    Joplin是一款开源免费的笔记软件,可以记录笔记.待办清单,支持Markdown,可导出Markdown格式.HTML格式.PDF格式的文档,具备自动同步功能,可定时自动备份到文件系统或网盘. Jo ...

  3. GitHub如何选择合适的license(许可证)

    license译为许可证,也可作为开源协议,它可以将自己创作的东西,授权给他人使用,并约定了使用者可以有的权利和必须遵从的义务.现在很多优秀的开源项目都有设置license,不同的license所约束 ...

  4. 从字符串某位置开始的递增串(dfs)注意for循环中下标的错误

    #include <iostream> #include <string> using namespace std; char res[50];int tag=1; void ...

  5. Java线程池七个参数详解

    Java多线程开发时,常常用到线程池技术,这篇文章是对创建java线程池时的七个参数的详细解释. 从源码中可以看出,线程池的构造函数有7个参数,分别是corePoolSize.maximumPoolS ...

  6. python 常用模块函数使用

    1.collections模块在内置数据类型(dict.list.set.tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter.deque.defaultdict ...

  7. 用 Java 写一个单例类?

    饿汉式单例 public class Singleton { private Singleton(){} private static Singleton instance = new Singlet ...

  8. 学习SVN02

    代码发布方案: 1,安装,优化 软件环境,(nginx,lvs)  <-------运维工程师 2,程序代码(不断更新).   <--------开发工程师,(开发,运维都可以发布) 3, ...

  9. 『忘了再学』Shell基础 — 6、Bash基本功能(输入输出重定向)

    目录 1.Bash的标准输入输出 2.输出重定向 (1)标准输出重定向 (2)标准错误输出重定向 (3)正确输出和错误输出同时保存 3.输入重定向 1.Bash的标准输入输出 我们前边一直在说,在Li ...

  10. 在tomcat布置项目

    1.将项目打成war包复制到tomcat-webapps 2.修改tomcat端口号 3.指定jdk 一.找到tomcat目录/bin 文件夹下的 catalina.bat文件 二.在文件中找到 ec ...