3代npm中的非确定性

前几节中提到的,你的node_modules目录结果和依赖树结果是由安装顺序决定的。

如果你,或者你的开发团队使用package.json,并且使用npm install命令行去添加包的话,那么你的node_modules目录结构是可能跟你同事的node_modules目录结构不一样的,跟你的工作台、测试环境或者生产环境,也可能不一样。

简而言之就是npm3安装依赖的时候,并不是以一种确定的行为安装的。

读到这你或许有些惊讶,不过在这一小节中我将解释为什么会发生这种情况,并且让你了解到这种情况对你的应用是没有什么问题的。如果你还担心的胡啊,那么我还会给出一些方法让你重建一个一致的node_modules目录。


示例

回到我们前面的例子来。

我们的应用依赖于ACDE模块,同时AE依赖于B V1.0,而CD依赖于B V2.0。

这种情况下,我们的package.json可能是下面这个样子:

{
  "name": "example3",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "mod-a": "^1.0.0",
    "mod-c": "^1.0.0",
    "mod-d": "^1.0.0",
    "mod-e": "^1.0.0"
  }
}

假设现在,我们团队中有一个人开发者决定去完成某个需求,而完成这个需求需要将模块A升级到2.0,而这带来的影响就是模块A依赖于模块B V2.0了,而不是之前的B V1.0。

因此,我们的同时使用npm install来升级到模块A的2.0版本:

npm install mod-a@2 --save

现在我们的目录结构应该是下图:

紧接着,我们的同时完成了这个需求之后,将这个需求推送到测试环境,并且使用npm install去安装package.json文件:

{
  "name": "example3",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "mod-a": "^2.0.0",
    "mod-c": "^1.0.0",
    "mod-d": "^1.0.0",
    "mod-e": "^1.0.0"
  }
}

那么这个时候,测试机子的依赖明显跟我们本地开发的机子的依赖树是不一样的。


记住:安装顺序决定一切

当我们的开发者使用npm install将模块A升级到2.0版本的时候,本质上是最后一个安装模块A V2.0的包。因为我们的开发者之前已经使用npm install来安装package.json中的依赖,这时候因为新需求而升级,就如同是最后一个安装模块A V2.0一般了。

安装模块A V2.0之后,模块A V1.0还是会继续留在顶层依赖中,因为模块E还依赖于模块A V1.0,因此2.0会被安装在模块A的嵌套依赖中。

而对于测试机子的话,项目是在一个新的文件夹中创建,并且之前是没有node_modeuls目录存在的。当npm install命令被运行的时候,它将会安装package.json来安装依赖。

现在,模块A V2.0会首先被安装,并且模块BV 2.0也会被安装在顶层依赖中,这个时候,不在是前面的B V1.0被安装在顶层依赖中。因为模块A V2.0这个时候是首先被安装,而不再是最后被安装。(npm是通过字母表顺序安装依赖的)

紧接着到了模块E被安装的时候,它所依赖的模块B V1.0因为顶层依赖模块B V2.0版本的存在,而被迫得安装在模块E的嵌套依赖之中。


依赖树的不同是否会影响我们的应用?

不会的。即使依赖树是不同的,但是通过这个依赖树,两者各自所需要的依赖都能够被安装并且正确地给出。因此,我们所需要的依赖还是能够被提供。


如果想要让node_modules目录结构一致,那么要如何做呢?

使用npm install去安装同一个package.json文件的时候,总能够输出一致的依赖树。这个是因为安装的时候,都是先安装在package.json中字母靠前的依赖。因此,相同的安装顺序能够让你获得相同的依赖树。

因此当你改变了package.json的时候,你可以通过删除你的node_modules,然后再重新使用npm install来获得一致的依赖树。


链接: https://fly63.com/course/21_1006