20、JS 的依赖管理

依赖文件:package.json

依赖版本:

1
2
3
4
5
6
"dependencies": {
"antd": "3.1.2",
"react": "~16.0.1",
"redux": "^3.7.2",
"lodash": "*"
}

"react": "~16.0.1"版本格式:[范围符号]主版本.次版本.修订版本

  • 主版本:不兼容的更改;平时不建议升级
  • 次版本:兼容的功能性新增;平时可以升级
  • 修订版本:兼容的问题修复;平时可以升级

范围符号:

  • *:升级到最新版本
  • ^:升级次版本和修订版本
  • ~:只升级修订版本

因此上述的版本范围为

1
2
3
4
5
6
"dependencies": {
"antd": "3.1.2", // === 3.1.2
"react": "~16.0.1", // [16.0.1, 16.1.0)
"redux": "^3.7.2", // [3.7.2, 4.0.0)
"lodash": "*" // 永远最新
}

依赖管理工具:npm、yarn、cnpm、pnpm 等

npm

  • v1:依赖嵌套,依赖的依赖放在各依赖下面,比如下面这样
1
2
3
4
5
6
7
8
9
10
11
12
13
14
node_modules
├── A@1.0.0
│ └── node_modules
│ └── B@1.0.0
├── C@1.0.0
│ └── node_modules
│ └── B@2.0.0
└── D@1.0.0
└── node_modules
└── B@1.0.0

优点:简单明了
缺点:嵌套太深,重复依赖;
B@1.0.0 存了两份
  • v3:扁平模式,相同的放在根层,冲突的还是放在依赖下面。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
node_modules
├── A@1.0.0
├── B@1.0.0
└── C@1.0.0
└── node_modules
└── B@2.0.0
├── D@1.0.0

require('A') 时,首先会在当前路径下搜索 node_modules 目录中是否存在该依赖,
如果不存在则往上查找,也就是继续查找该路径的上一层目录下的 node_modules

优点:避免嵌套太深,消除重复依赖
缺点:该版本还缺少 lock 文件,不确定性
什么是确定性?始终得到相同的 node_modules 目录结构
  • v5:node_modules 目录结构跟 v3 一样,但新增了package-lock.json文件,保证依赖的确定性
1
2
3
"dependencies": {
"redux": "^3.7.2"
}

对应的package-lock.json,记录了每一个依赖的确定版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
{
"name": "redux",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "redux",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"redux": "^3.7.2"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
},
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
"bin": {
"loose-envify": "cli.js"
}
},
"node_modules/redux": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz",
"integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==",
"dependencies": {
"lodash": "^4.2.1",
"lodash-es": "^4.2.1",
"loose-envify": "^1.1.0",
"symbol-observable": "^1.0.3"
}
},
"node_modules/symbol-observable": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
"integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
"engines": {
"node": ">=0.10.0"
}
}
}
}

yarn

yarn 发布时是为了解决 npm v3 的问题
yarn 生成的 node_modules 目录结构和 npm v5 是相同的,同时默认生成一个 yarn.lock 文件。
特点:yarn.lock 文件里仍然会出现语义化版本范围符号(~^*)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==

lodash-es@^4.2.1:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==

lodash@^4.2.1:
version "4.17.21"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==

loose-envify@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
dependencies:
js-tokens "^3.0.0 || ^4.0.0"

redux@^3.7.2:
version "3.7.2"
resolved "https://registry.yarnpkg.com/redux/-/redux-3.7.2.tgz#06b73123215901d25d065be342eb026bc1c8537b"
integrity sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==
dependencies:
lodash "^4.2.1"
lodash-es "^4.2.1"
loose-envify "^1.1.0"
symbol-observable "^1.0.3"

symbol-observable@^1.0.3:
version "1.2.0"
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==

cnpm

它使用链接 link 的安装方式,提高了安装速度。
它生成的 node_modules 目录采用的是以 版本号 @包名 命名,然后再做软链接到只以包名命名的文件夹上。

优点:按照速度快
缺点:不会生成 lock 文件;生成的 node_modules 目录不一致

pnpm

使用内容寻址存储来存储依赖包,相同的包(不论被多少个项目所使用)只会在存储中存储一次
它生成的 node_modules 目录如下:直接依赖放在根目录,依赖的依赖放在 .pnpm 文件夹内

默认生成一个 pnpm-lock.yaml 文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
lockfileVersion: 5.4

specifiers:
redux: ^3.7.2

dependencies:
redux: 3.7.2

packages:

/js-tokens/4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
dev: false

/lodash-es/4.17.21:
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
dev: false

/lodash/4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
dev: false

/loose-envify/1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
dependencies:
js-tokens: 4.0.0
dev: false

/redux/3.7.2:
resolution: {integrity: sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==}
dependencies:
lodash: 4.17.21
lodash-es: 4.17.21
loose-envify: 1.4.0
symbol-observable: 1.2.0
dev: false

/symbol-observable/1.2.0:
resolution: {integrity: sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==}
engines: {node: '>=0.10.0'}
dev: false

循环依赖:
A 依赖 B,B 依赖 A

幽灵依赖:
项目中用了的包,但未在 package.json 中定义。
这是因为依赖提升造成的副作用


20、JS 的依赖管理
https://mrhzq.github.io/职业上一二事/前端面试/每日知识卡片/20、JS 的依赖管理/
作者
黄智强
发布于
2024年2月3日
许可协议