实操理解node_modules目录结构

本文通过实例探讨npm不同版本下node_modules目录结构的变化,包括扁平化结构、依赖版本冲突解决、lock文件重要性及pnpm的离线缓存特性。详细解析了在安装element-plus、dayjs等包后,如何影响项目中其他依赖的版本选择和目录布局。

环境(2022-8-16):

`node -v`
> v16.15.1

`npm -v`
> 8.11.0

`yarn -v`
> 1.22.19

`pnpm -v`
> 7.9.0

npm0:

mkdir npm0
cd npm0
npm install element-plus --save

此时的目录结构:

+-- node_modules
|   +-- ...
|   +-- dayjs@1.10.4
|   +-- element-plus
|   +-- vue
|   +-- ...
+-- package.json

解析: 这是因为在npm3之后采用了扁平结构,vue是element-plus的依赖,会提升到顶层,形成这样的目录结构,node_modules下其他的依赖也是如此。

此时在目录下再添加index.html文件,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div id="app">{{ message }}</div>
</body>
<script src="bundle.js"></script>
</html>

添加index.js文件 ,代码如下:

const vue = require('vue')

const { createApp } = vue

createApp({
  data () {
    return {
      message: 'Hello Vue!'
    }
  }
}).mount('#app')

添加 browserify依赖

npm install browserify -D

在package.json中添加打包脚本

"build": "browserify index.js > bundle.js"

 运行打包脚本:

npm run build

然后打开html.index,可正常显示。

 为什么项目依赖中里没有添加vue,但是却可以却是可以使用呢?这是因为node_modules的扁平结构,element-plus依赖了vue,所以可以项目中使用,这也就是所谓的幽灵依赖。


npm1:

mkdir npm1
cd npm1
npm install dayjs@1.11.2 --save

此时的目录结构:

+-- node_modules
|   +-- dayjs@1.11.2
+-- package.json

此时的package.json :

{
  "dependencies": {
    "dayjs": "^1.11.2"
  }
}

然后安装element-plus 

npm install element-plus --save

 安装完成后,新的目录结构

+-- node_modules
|   +-- ...
|   +-- dayjs@1.11.5
|   +-- element-plus@2.2.13
|   +-- ...
+-- package.json

解析: 可以在element-plus的package.json中看到,element-plus也依赖了dayjs

"dayjs": "^1.11.3"

element-plus声明依赖dayjs的最低版本为1.11.3,项目中声明dayjs的最低版本为1.11.2,所以提升到当前的最新版本1.11.5


npm2:

mkdir npm2
cd npm2
npm install element-plus --save

此时的目录结构

+-- node_modules
|   +-- ...
|   +-- element-plus
|   +-- dayjs@1.11.5
|   +-- ...
+-- package.json

此时的package.json : 

{
  "dependencies": {
    "element-plus": "^2.2.13"
  }
}

然后安装dayjs 

npm install dayjs@1.11.2 --save

安装完成后新的目录结构:

+-- node_modules
|   +-- ...
|   +-- dayjs@1.11.2
|   +-- element-plus
|   |   +-- node_modules
|   |   |   +-- dayjs@1.11.5
|   +-- ...
+-- package.json

新的package.json:

{
  "dependencies": {
    "dayjs": "^1.11.2",
    "element-plus": "^2.2.13"
  }
}

 解析:就算当前项目中已通过间接依赖存在了dayjs,若再安装指定版本,还是会优先安装指定的版本。

若指定版本不满足其他包的版本要求,则会在对应包下再安装一份满足条件的版本;

若指定版本满足其他包的版本要求,则会统一使用新的依赖版本(下面是一个具体举例说明);

//  若当时dayjs时指定版本为1.11.4

// npm install dayjs@1.11.4 --save

// 则生成的目录结构如下:

+-- node_modules
|   +-- ...
|   +-- dayjs@1.11.4
|   +-- element-plus
|   +-- ...
+-- package.json

 npm3:

mkdir npm2

cd npm2

npm install element-plus --save
npm install ant-design-vue --save

此时的目录结构:

+-- node_modules
|   +-- ...
|   +-- ant-design-vue
|   +-- element-plus
|   +-- dayjs@1.11.5
|   +-- ...
+-- package.json

然后安装dayjs

+-- node_modules
|   +-- ...
|   +-- dayjs@1.10.4
|   +-- ant-design-vue
|   |   +-- node_modules
|   |   |   +-- dayjs@1.11.5
|   +-- element-plus
|   |   +-- node_modules
|   |   |   +-- dayjs@1.11.5
|   +-- ...
+-- package.json 

可以看到 ant-design-vue和element-plus没有共享dayjs这个依赖


 npm4:

模拟从代码仓库clone代码:拷贝npm3下的package.json过来, 然后安装依赖

npm install

此时npm4的目录结构:

+-- node_modules
|   +-- ...
|   +-- dayjs@1.11.5
|   +-- ant-design-vue
|   +-- element-plus
|   +-- ...
+-- package.json

但是npm3的目录结构却不一样: 

+-- node_modules
|   +-- ...
|   +-- dayjs@1.10.4
|   +-- ant-design-vue
|   |   +-- node_modules
|   |   |   +-- dayjs@1.11.5
|   +-- element-plus
|   |   +-- node_modules
|   |   |   +-- dayjs@1.11.5
|   +-- ...
+-- package.json

 同样的代码,同样的脚本,但是生成的依赖不同,这是因为没有锁定版本。


npm5:

和npm4做相同的事情,但是拷贝时,需要把package-lock.json一起拷贝过来

npm install

此时npm5的目录结构:

+-- node_modules
|   +-- ...
|   +-- dayjs@1.10.4
|   +-- ant-design-vue
|   |   +-- node_modules
|   |   |   +-- dayjs@1.11.5
|   +-- element-plus
|   |   +-- node_modules
|   |   |   +-- dayjs@1.11.5
|   +-- ...
+-- package.json

可以看到和npm3的结构是完全一样的:

+-- node_modules
|   +-- ...
|   +-- dayjs@1.10.4
|   +-- ant-design-vue
|   |   +-- node_modules
|   |   |   +-- dayjs@1.11.5
|   +-- element-plus
|   |   +-- node_modules
|   |   |   +-- dayjs@1.11.5
|   +-- ...
+-- package.json

上传package-lock.json这类lockFile是很有必要的,比如前段时间发布的vue2的最后一个版本vue2.7(代号Naruto)支持了Composition Api 这就是同一个大版本中的重大更新,lockFile可以有效避免团队间因本地代码依赖不同产生的问题。


npm6: 

mkdir npm6
cd npm6

npm install element-plus --save
npm install ant-design-vue --save
npm install dayjs@1.10.4 --save
+-- node_modules
|   +-- ...
|   +-- dayjs@1.10.4
|   +-- ant-design-vue
|   |   +-- node_modules
|   |   |   +-- dayjs@1.11.5
|   +-- element-plus
|   |   +-- node_modules
|   |   |   +-- dayjs@1.11.5
|   +-- ...
+-- package.json

然后执行命令

npm dedupe

 可以看到输出:

removed 2 packages, changed 1 package, and audited 64 packages in 2s

然后依赖的目录结构也发生了变化:

+-- node_modules
|   +-- ...
|   +-- ant-design-vue
|   +-- element-plus
|   +-- dayjs@1.11.5
|   +-- ...
+-- package.json

下面是官方对这个命令的解释

Searches the local package tree and attempts to simplify the overall structure by moving dependencies further up the tree, where they can be more effectively shared by multiple dependent packages

npm7: 

此时先断网,然后拷贝npm3下的package.json过来安装依赖

npm install

输出:

added 63 packages in 45s

 npm采用了离线缓存,下面这个命令可以看到缓存列表

npm cache ls

pnpm3:

拷贝npm3下的package.json过来, 然后安装依赖

pnpm install

会看到报错:

 Unmet peer dependencies
 Peer dependencies that should be installed:
 vue@">=3.2.0 <4.0.0"

此时需要添加vue依赖:

pnpm add vue --save
然后再install后成功,安装成功后的目录结构:
+-- node_modules
|   +-- .pnpm
|   |   +-- ...
|   |   +-- ant-design-vue@3.2.11
|   |   |   +-- node_modules
|   |   |   |   +-- ...
|   |   |   |   +-- dayjs@1.11.5
|   |   |   |   +-- ...
|   |   +-- dayjs@1.11.5
|   |   +-- element-plus@2.2.13
|   |   |   +-- node_modules
|   |   |   |   +-- ...
|   |   |   |   +-- dayjs@1.11.5
|   |   |   |   +-- ...
|   +-- ant-design-vue
|   +-- dayjs
|   +-- element-plus
|   +-- vue
+-- package.json
+-- pnpm-lock.yaml

在文件资源管理器里可以看到ant-design-vue, dayjs 这些重复依赖都是以符号链接的形式存在,而且依赖结构也没有扁平化。 


npm yarn pnpm 发展历程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

okey573

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值