npm依赖结构解析

npm 基本命令

npm install 命令用来安装依赖到node_modules目录。

当执行这条命令的时候npm会先去查看当前node_modules里面是否已经有这个包的,如果没有才会进行安装。

go 复制代码
npm install <package name>

如果你希望node_modules无论什么情况下都要安装,那么你可以安装的时候加上一个-f的参数

go 复制代码
npm install <package name> -f

如果你想更新已安装的某个包的版本,你可以用如下命令

go 复制代码
npm update <package name>

npm包的发布

npm包版本后缀

sql 复制代码
Alpha 代表内部测试版本
Beta 代表公开的广泛测试版本
RC 代表修复问题和缺陷的候选版本
Release 代表最终的可靠版本

npm的发展过程

npm2--嵌套地狱

早期的时候,npm安装依赖的时候是完全按照层级关系去嵌套安装的。这会导致嵌套地狱的产生。

比如:A@1.0.0的依赖是:B@1.0.0,C@1.0.0的依赖是:B@1.0.0、D@1.0.0。那么npm安装之后结构就是下面这种情况。

kotlin 复制代码
node_modules
├── A@1.0.0
│   └── node_modules
│       └── B@1.0.0
└── C@1.0.0
    └── node_modules
        └── B@1.0.0
        └── D@1.0.0

这种嵌套方式虽然结构清晰明了,但是多个依赖如果都依赖同个包的话,这个包会被下载多次,会导致node_modules的体积过于庞大。

npm3--扁平化嵌套、不确定性、幽灵依赖

扁平化嵌套

针对npm2嵌套地狱的问题,npm3作出了解决方案,就是采用扁平化嵌套方式。

无论是直接依赖还是子依赖的依赖,优先安装到node_modules的根目录下。当安装到相同模块的时候,会判断已安装模块是否符合新模块的版本范围,如何符合则跳过安装,不符合则安装在当前模块的node_modules下面。

比如:项目依赖了A、C、D,A依赖B@v1,C依赖B@v2,D依赖E@v1。那么npm安装之后结构就是下面这种情况

css 复制代码
node_modules
├── A
├── B@v1
├── C
   └── node_modules
        └── B@v2
├── D
└──E@v1

这种嵌套方案可以避免同个包被安装多次,也可以避免嵌套层级太深。但是它又会产生新的问题:幽灵依赖、不确定性。

幽灵依赖

比如:项目依赖了A、C、D,A依赖B@v1,C依赖B@v2,D依赖E@v1。那么npm安装之后结构就是下面这种情况

css 复制代码
node_modules
├── A
├── B@v1
├── C
   └── node_modules
        └── B@v2
├── D
└──E@v1

有些时候,我们的项目根本没有直接依赖B@v1,但是因为扁平化,导致了间接依赖B@v1被提升到了顶级,我们在项目中就可以直接导入B@v1进行使用。但是如果后面我们删除了A包,那么node_modules结构就会变成下面这种结构,那我们之前导入B@v1的那段代码就会报错。

css 复制代码
node_modules
├── C
├──B@v2
├── D
└──E@v1

node_modules结构的不确定性

因为存在依赖提升,所以node_modules的结构根据安装包的顺序不同,可能会发生变化,举例如下:

假如我目前在准备项目的一些前置依赖,然后我的安装顺序如下:

A -> C(依赖lodash@3) -> B(依赖lodash@2),那么我的node_modules的结构如下

css 复制代码
node_modules
├── A
├──lodash@3
├── B
   └── node_modules
        └── lodash@2
└── C

但是package.json是按照字典排序将这些包添加在依赖字段中的。下一个开发者如果按照pakcage.json去安装,那么他的安装顺序和node_modules结构如下:

A -> B(依赖lodash@2) -> C(依赖lodash@3)

css 复制代码
node_modules
├── A
├──lodash@2
├── B
└── C
    └── node_modules
        └── lodash@3

从上面就可以看出两者node_modules结构的不确定性

package-lock.json文件的解析

假如有这么一个package.json,文件内容如下

json 复制代码
{
  "name": "my-app",   // 包的名字
  "version": "1.0.0", // 包的版本
  "dependencies": {   // 包的运行依赖
    "base64-js": {    // 所依赖的包1
      "version": "1.0.1", // 包的版本
      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.0.1.tgz", // 包的安装来源
      "integrity": "sha1-aSbRsZT7xze47tUTdW3i/Np+pAg="
    },
    "buffer": {
      "version": "5.4.3",
      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz",
      "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==",
      "requires": { // buffer的依赖
        "base64-js": "^1.0.2",
        "ieee754": "^1.1.4"
      },
      "dependencies": { // buffer的依赖,真正安装在buffer的node_modules下面的依赖
        "base64-js": {
          "version": "1.3.1",
          "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
          "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
        }
      }
    },
    "ieee754": {
      "version": "1.1.13",
      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
      "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
    },
    "ignore": {
      "version": "5.1.4",
      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz",
      "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A=="
    }
  }
}

为了解决npm install的不确定性的问题,npm5引进了package-lock.json。只要项目中有package-lock.json,所有开发者都可以通过npm install按照package-lock.json的规则去安装包,而package-lock.json的dependencies可以解决这种不确定性。但是这依然无法解决幽灵依赖问题

参考文章:
npm 模块安装机制简介
彻底了解npm------架构、进化史及原理解析
聊聊依赖管理
前端工程化 - 剖析npm的包管理机制

npm的进化史

相关推荐
杏花春雨江南8 小时前
npm error Could not resolve dependency:
前端·npm·node.js
yeyuningzi8 小时前
npm升级提示error engine not compatible with your version of node/npm: npm@11.6.2
前端·npm·node.js
wyzqhhhh8 小时前
npm相关知识
前端·npm·node.js
清灵xmf11 小时前
npm install --legacy-peer-deps:它到底做了什么,什么时候该用?
前端·npm·node.js
只_只12 小时前
npm install sqlite3时报错解决
前端·npm·node.js
三十_14 小时前
团队踩坑实录:用 patch-package 临时修复第三方依赖的最佳实践
前端·npm
Icoolkj14 小时前
npm、npx、pnpm 深度解析:从原理到实战的全方位指南
前端·npm·node.js
尘埃不入你眼眸14 小时前
powerShell无法执行npm问题
前端·npm·node.js
我有一棵树14 小时前
npm uninstall 执行的操作、有时不会删除 node_modules 下对应的文件夹
前端·npm·node.js