主要探究不同 dependencies 配置对项目的影响
一、devDependencies
添加 devDependencies 依赖的方式
npm install <package-name> --save-dev
// 缩写
npm i <package-name> -D
该配置项放置本地开发过程中需要使用到的编译、打包、测试、格式化模块等
安装依赖的时候,不会安装依赖的 devDependencies
二、dependencies
添加 dependencies 依赖的方式
npm install <package-name>
// 缩写
npm i <package-name>
项目中实际运行需要用到的代码,没有的话会出错
1. 唯一依赖
例如:faker-project 项目依赖了 sdk-a
// faker-project
{
"name": "faker-project",
"dependencies": {
"sdk-a": "1.0.0"
}
}
而 sdk-a 的 dependencies 中包含了 sdk-core
// sdk-a
{
"name": "sdk-a",
"version":"1.0.0",
"dependencies": {
"sdk-core": "0.0.1"
}
}
则 faker-project 执行 npm install 之后,目录结构如下
faker project
|
├── node_modules
| ├── sdk-a
| └── sdk-core
|
└── package.json
所有依赖会平级设置
2. 重复依赖
2.1 不兼容
假设 faker-project 项目又依赖了 sdk-b
// faker-project
{
"name": "faker-project",
"dependencies": {
"sdk-a": "1.0.0",
+ "sdk-b": "1.0.0"
}
}
而 sdk-b 恰好也依赖了 sdk-core,但是 sdk-core 版本不同
// sdk-b
{
"name": "sdk-b",
"version":"1.0.0",
"dependencies": {
"sdk-core": "0.0.2"
}
}
则 faker-project 执行 npm install 之后,目录结构如下
faker project
|
├── node_modules
| ├── sdk-a
+ | ├── sdk-b
+ | | └── node_modules
+ | | └── sdk-core // 0.0.2
+ | |
| └── sdk-core // 0.0.1
|
└── package.json
依赖会在自己的 node_modules 中单独安装一份,避免冲突
2.2 兼容
如果 sdk-core 的版本能够兼容
// sdk-a
{
"name": "sdk-a",
"version":"1.0.1",
"dependencies": {
- "sdk-core": "0.0.1"
+ "sdk-core": "^0.0.1"
}
}
则两者会共用一份依赖(如果先安装一个,再安装另一个。最后目录结构也会和不兼容的情况表现一致)
faker project
|
├── node_modules
| ├── sdk-a
| ├── sdk-b
| └── sdk-core // 0.0.2
|
└── package.json
3. 历史
在 npm 3 之前,node_modules 不会平级设置。依赖的依赖都会直接嵌套
三、peerDependencies
一理解为「同级依赖」
用在发布的代码库当中,表示需要宿主环境提供该配置下的模块依赖,与宿主环境息息相关。npm(3.x 版本之后,7.x 之前)、yarn 不会自动安装该配置下的依赖模块,会告警提示。
时间节点:
npm 3 - 2015 年 5 月
npm 5 - 2017 年 5 月
yarn 1 - 2017 年 9 月
yarn 2 - 2020 年 1 月
npm 7 - 2021 年 3 月
PS:为了便于理解,下文中:
- 新版:npm 7 及其以上的版本,会自动安装 peerDependencies
- 旧版:npm 3.x ~ 6.x 和 yarn,不会自动安装 peerDependencies
1. 唯一依赖
// sdk-a
{
"name": "sdk-a",
"version":"1.0.2",
"peerDependencies": {
"sdk-core": "^0.0.1"
}
}
1.1 旧版
不会自动安装该配置下的依赖模块,会告警提示。需要用户自行安装
warning " > sdk-a@1.0.3" has unmet peer dependency "sdk-core@^0.0.1".
faker project
|
├── node_modules
| └── sdk-a
|
└── package.json
1.2 新版
会自动安装,并始终只存在一个。直接位于 node_modules 之下
1.3 区别
不管自动还是手动,最后的结果都是。peerDependencies 中的依赖都会被直接安装在 node_modules 之下
最大区别是,旧版通过自己的手动安装。会体现在项目的 dependencies 中,而新版不会
// faker-project
{
"name": "faker-project",
"dependencies": {
"sdk-a": "1.0.3",
"sdk-core": "^0.0.1" // 最大区别
}
}
2. 重复依赖
2.1 不兼容
2.1.1 旧版
只会在安装时提示不同版本的 peer dependency 信息
warning " > sdk-a@1.0.4" has unmet peer dependency "sdk-core@0.0.1".
warning " > sdk-b@1.0.2" has unmet peer dependency "sdk-core@0.0.2".
2.1.2 新版
对于版本不兼容的依赖,安装时候会直接报错
可以通过 --legacy-peer-deps
让 peerDependencies 不自动安装
2.1.3 如何处理不兼容的 peerDependencies
目前没有让不兼容的 peerDependencies 各自生效的方法。所以真碰到了这种情况,一般处理方法是修改其中一个带有 peerDependencies 依赖的包版本。让其依赖另一版本的 peerDependencies 和其余版本的兼容
2.2 兼容
// sdk-b
{
"name": "sdk-b",
"version":"1.0.3",
"peerDependencies": {
"sdk-core": "^0.0.1"
}
}
// faker-project
{
"name": "faker-project",
"dependencies": {
"sdk-a": "1.0.4",
"sdk-b": "1.0.3"
}
}
多个项目存在兼容 peerDependencies 的情况
2.2.1 旧版
不自动安装,仅提示
2.2.2 新版
自动安装,和唯一依赖行为一样
2.3 特殊情况
如果 sdk-core,同时存在 peerDependencies 和 dependencies 时
2.3.1 旧版
不会被安装,等同于只有 peerDependencies
2.3.2 新版
会自动安装,等同于只有 dependencies
两种情况均不判断版本兼容
2.4 嵌套依赖
还有更极端的情况,比如 dependencies 里如果有 peerDependencies。详情见下面的文章
四、总结
- 运行时用不到的依赖,放在 devDependencies 中
- 插件类的依赖(比如 sdk-core 是一个依赖,在此基础上开发的依赖 sdk-a、sdk-b)才使用 peerDependencies
- 要求运行时时单例的依赖(vue、react 等同时只能存在一个实例)使用 peerDependencies
- 其余情况都使用 dependencies
五、其他 dependencies
其他比较少见的 dependencies
1. optionalDependencies
optionalDependencies 可选依赖,如果有一些依赖包即使安装失败,项目仍然能够运行或者希望 npm 继续运行,就可以使用 optionalDependencies。另外 optionalDependencies 会覆盖 dependencies 中的同名依赖包,所以不要在两个地方都写
举个栗子,可选依赖包就像程序的插件一样,如果存在就执行存在的逻辑,不存在就执行另一个逻辑。
try {
var foo = require('foo')
var fooVersion = require('foo/package.json').version
} catch (er) {
foo = null
}
if ( notGoodFooVersion(fooVersion) ) {
foo = null
}
// .. then later in your program ..
if (foo) {
foo.doFooThings()
}
2. bundledDependencies / bundleDependencies
打包依赖,bundledDependencies 是一个包含依赖包名的数组对象,在发布时会将这个对象中的包打包到最终的发布包里。如:
{
"name": "fe-weekly",
"description": "ELSE 周刊",
"version": "1.0.0",
"main": "index.js",
"devDependencies": {
"fw2": "^0.3.2",
"grunt": "^1.0.1",
"webpack": "^3.6.0"
},
"dependencies": {
"gulp": "^3.9.1",
"hello-else": "^1.0.0"
},
"bundledDependencies": [
"fw2",
"hello-else"
]
}
执行打包命令 npm pack
, 在生成的 fe-weekly-1.0.0.tgz 包中,将包含 fw2 和 hello-else。 但是值得注意的是,这两个包必须先在 devDependencies 或 dependencies 声明过,否则打包会报错。
参考
你需要知道的几类 npm 依赖包管理 - https://zhuanlan.zhihu.com/p/29855253
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。