npm install安装机制

709 阅读3分钟

image.png 引用:cloud.tencent.com/developer/a… 该流程图来梳理npm install安装机制

npm install, 首先会检查和获取 npm的配置, 优先级为:

项目级的.npmrc文件 > 用户级的 .npmrc文件 > 全局级的 .npmrc > npm内置的 .npmrc 文件

然后检查项目中是否有 package-lock.json文件

  • 如果有, 检查 package-lock.jsonpackage.json声明的依赖是否一致:

    • 一致, 直接使用package-lock.json中的信息,从网络或者缓存中加载依赖
    • 不一致, 根据上述流程中的不同版本进行处理
  • 如果没有, 那么会根据package.json递归构建依赖树,然后就会根据构建好的依赖去下载完整的依赖资源,在下载的时候,会检查有没有相关的资源缓存:

    • 存在, 直接解压到node_modules文件中
    • 不存在, 从npm远端仓库下载包,校验包的完整性,同时添加到缓存中,解压到 node_modules

最后, 生成 package-lock.json 文件,同一个项目团队,应该保持npm 版本的一致性。防止安装过程造成

安装文件概念

1、node_modules
2、package-lock.json文件
3、package.json文件

一、node_modules

npm 3.x 采用了扁平化的方式来安装模块

  • 安装模块时,不管其是直接依赖还是子依赖的依赖,优先将其安装在 node_modules 根目录。
  • 安装到相同模块时,判断已安装的模块版本是否符合新模块的版本范围,如果符合则跳过,不符合则在当前模块的 node_modules 下安装该模块。(该方式下会存在,同时安装多个不同版本的模块,并且会随着顺序的变动,每次生成的node_modules结构不一致,)
  • 另外,为了让开发者在安全的前提下使用最新的依赖包,package.json 通常只会锁定大版本,这意味着在某些依赖包小版本更新后,同样可能造成依赖结构的改动,依赖结构的不确定性可能会给程序带来不可预知的问题。
{
  "name": "test-npm",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "axios": "^0.26.0",
    "fetch": "^1.1.0"
  }
}

image.png

二、package-lock.json

为了解决 npm install 的不确定性问题,在 npm 5.x 版本新增了 package-lock.json 文件,而安装方式还沿用了 npm 3.x 的扁平化的方式。
package-lock.json 的作用是锁定依赖结构,即只要你目录下有 package-lock.json 文件,那么你每次执行 npm install 后生成的 node_modules 目录结构一定是完全相同的。

项目中使用了 package-lock.json 可以显著加速依赖安装时间。
package-lock.json 中缓存了每个包的具体版本和下载链接,不需要再去远程仓库进行查询,然后直接进入文件完整性校验环节,减少了大量网络请求。

该package-lock.json文件下,对应的node_modules目录结构一致

{
  "name": "test-npm",
  "version": "1.0.0",
  "lockfileVersion": 1,
  "requires": true,
  "dependencies": {
    "axios": {
      "version": "0.26.0",
      "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.0.tgz",
      "integrity": "sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==",
      "requires": {
        "follow-redirects": "^1.14.8"
      }
    },
    "biskviit": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/biskviit/-/biskviit-1.0.1.tgz",
      "integrity": "sha1-A3oM1LcbnjMf2QoRIt4X3EnkIKc=",
      "requires": {
        "psl": "^1.1.7"
      }
    },
    "encoding": {
      "version": "0.1.12",
      "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
      "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
      "requires": {
        "iconv-lite": "~0.4.13"
      }
    },
    "fetch": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/fetch/-/fetch-1.1.0.tgz",
      "integrity": "sha1-CoJ58Gvjf58Ou1Z1YKMKSA2lmi4=",
      "requires": {
        "biskviit": "1.0.1",
        "encoding": "0.1.12"
      }
    },
    "follow-redirects": {
      "version": "1.14.8",
      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz",
      "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA=="
    },
    "iconv-lite": {
      "version": "0.4.24",
      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
      "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=",
      "requires": {
        "safer-buffer": ">= 2.1.2 < 3"
      }
    },
    "psl": {
      "version": "1.8.0",
      "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
      "integrity": "sha1-kyb4vPsBOtzABf3/BWrM4CDlHCQ="
    },
    "safer-buffer": {
      "version": "2.1.2",
      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
      "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo="
    }
  }
}

使用建议

开发系统应用时,建议把 package-lock.json 文件提交到代码版本仓库,从而保证所有团队开发者以及 CI 环节可以在执行 npm install 时安装的依赖版本都是一致的。

在开发一个 npm包 时,你的 npm包 是需要被其他仓库依赖的,如果你锁定了依赖包版本,你的依赖包就不能和其他依赖包共享同一范围内的依赖包。

三、package.json

node 中5种依赖:

  • dependencies - 业务依赖
  • devDependencies - 开发依赖
  • peerDependencies - 同伴依赖
  • bundledDependencies / bundleDependencies - 打包依赖
  • optionalDependencies - 可选依赖

我们常用的依赖是dependenciesdevDependencies,剩下三种依赖则是作为包的发布者才会使用到的字段。

dependencies

这种依赖在项目最终上线或者发布npm包时所需要,即其中的依赖项应该属于线上代码的一部分。比如框架vue,第三方的组件库element-ui等,这些依赖包都是必须装在这个选项里供生产环境使用。

通过命令`npm install/i packageName 安装

devDependencies

开发依赖。比如构建工具webpackgulp,预处理器babel-loaderscss-loader,这些都是辅助开发的工具包,无须在生产环境使用。

通过命令npm install/i -D 把包安装成开发依赖。

千万别以为只有在dependencies中的模块才会被一起打包,而在devDependencies中的不会!模块能否被打包,取决于项目里是否被引入了该模块!

在业务项目中dependenciesdevDependencies没有什么本质区别,只是单纯的一个规范作用,在执行npm i时两个依赖下的模块都会被下载;而在发布npm包的时候,包中的dependencies依赖项在安装该包的时候会被一起下载,devDependencies依赖项则不会。

其他的依赖详细见:juejin.cn/post/684490…

引用链接:
juejin.cn/post/706084…
cloud.tencent.com/developer/a… juejin.cn/post/684490…