引用:cloud.tencent.com/developer/a… 该流程图来梳理npm install安装机制
npm install, 首先会检查和获取 npm的配置, 优先级为:
项目级的.npmrc文件 > 用户级的 .npmrc文件 > 全局级的 .npmrc > npm内置的 .npmrc 文件
然后检查项目中是否有 package-lock.json文件
-
如果有, 检查
package-lock.json和package.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"
}
}
二、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 - 可选依赖
我们常用的依赖是dependencies和devDependencies,剩下三种依赖则是作为包的发布者才会使用到的字段。
dependencies
这种依赖在项目最终上线或者发布npm包时所需要,即其中的依赖项应该属于线上代码的一部分。比如框架vue,第三方的组件库element-ui等,这些依赖包都是必须装在这个选项里供生产环境使用。
通过命令`npm install/i packageName 安装
devDependencies
开发依赖。比如构建工具webpack、gulp,预处理器babel-loader、scss-loader,这些都是辅助开发的工具包,无须在生产环境使用。
通过命令npm install/i -D 把包安装成开发依赖。
千万别以为只有在
dependencies中的模块才会被一起打包,而在devDependencies中的不会!模块能否被打包,取决于项目里是否被引入了该模块!
在业务项目中dependencies和devDependencies没有什么本质区别,只是单纯的一个规范作用,在执行npm i时两个依赖下的模块都会被下载;而在发布npm包的时候,包中的dependencies依赖项在安装该包的时候会被一起下载,devDependencies依赖项则不会。
其他的依赖详细见:juejin.cn/post/684490…
引用链接:
juejin.cn/post/706084…
cloud.tencent.com/developer/a…
juejin.cn/post/684490…