现代JavaScript项目离不开npm(包管理器),如果我们使用npm来管理项目,那么可以在package.json中查看相应的依赖结构,通过npm install即可安装项目所需的所有依赖模块。
事实上,在npm文档中声明了五种项目里可能用到的dependency,对于开发者而言,需要明白具体场景下dependency的安装和使用。
Dependency 类型
1. dependencies
这类依赖确保你的应用能正常运行,依赖包需要被打包进最终的生产文件中。例如:
"dependencies": {    
  "axio": "0.19.0",
  "react": "^16.12.0",
  "react-dom": "^16.12.0",
}
复制代码2. devDependencies
与dependencies相反,devDependencies不应该打包进生产文件中 ,它包含你开发时用到的依赖包,通常用于项目构建或测试。例如:
"devDependencies": {    
  "@types/react": "16.8.23",
  "@typescript-eslint/parser": "2.8.0",
  "eslint": "^5.16.0",
  "lerna": "^3.16.4",
  "prettier": "^1.18.2",
  "rollup": "^1.0.0",
  "typescript": "^3.6.4"
}
复制代码大多情况下,以下依赖应被列举在devDependencies而不是dependencies:
- 
TS语法提示库: @types/react、@types/node那列举的这些第三方库永远会是 devDependencies?其实不是,例如你在开发一个有关ESLint的脚手架,需要运行ESLint的相关功能,此时ESLint应该是dependencies。一个依赖是devDependencies还是dependencies不是包本身决定的,而是这个依赖在具体项目中的职责和定位。
3. peerDependencies
具有peerDependencies的项目通常不是最终应用,这个项目会被宿主应用作为一个插件或第三方库消费。
peerDependencies的存在,主要是期望宿主应用安装这些依赖,让相同依赖不会在宿主应用和库中被重复安装。
同时为了减少库或插件的大小的目的,干脆将一些依赖统一放到宿主应用安装。
// antd package.json peerDependencies
"peerDependencies": {    
  "react-dom": ">=16.9.0"
}
// 如果宿主应用执行npm install发现没有react-dom依赖时,安装过程中会警告提醒
npm WARN antd@4.16.3 requires a peer of react-dom@>=16.9.0 but none is installed. You must install peer dependencies yourself.
复制代码peerDependencies还提供了peerDependenciesMeta来扩充peerDependencies信息
"peerDependencies": {    
  "react-dom": ">=16.9.0"
}
"peerDependenciesMeta": {
  "react-dom": {
    "optional": true
  }
}
// 如此配置宿主应用执行npm install即使没有react-dom依赖时,安装过程中也不会警告提醒
复制代码4. optionalDependencies
与dependencies类似,optionalDependencies是个可选的dependencies,npm在安装dependencies过程中出错会退出安装,但对optionalDependencies来说,即使一些依赖安装失败,也不影响最终应用运行,但还要做好相应模块容错处理。
// 模块可能安装失败,为避免模块找不到报错,使用try catch包裹
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()
}
复制代码注意:optionalDependencies会覆盖dependencies中的相同依赖。
5. bundledDependencies
如果期望一些依赖包能出现在最终打包的包里,可以将这些依赖放在bundledDependencies中,与其他dependencies不同的是,bundledDependencies接收一个包含依赖名的数组,例如:
{
  "name": "myReact",
  "version": "1.0.0",
  "bundledDependencies": [
    "react", "react-dom"
  ],
}
复制代码npm pack后会生成myReact-1.0.0.tgz,在npm install /path/to/myReact-1.0.0.tgz时,会把bundledDependencies中的依赖一并安装。
peerDependencies的问题与解决方案
实际开发中,dependencies和devDependencies使用最频繁,optionalDependencies和bundledDependencies则很少使用,对于剩下的peerDependencies,从npm 4开始,由于其deduplication algorithm去重算法带来技术上的挑战,npm不支持在npm install时自动安装peerDependencies,但到了20年发布的npm 7,npm使用Arborist algorithm 支持npm instal自动安装peerDependencies。
那使用npm 4 - 6的开发者,如果在package.json中声明了peerDependencies,执行npm install后这些依赖依然不会被安装。例如:
// npm 4 - 6  npm install不会自动安装以下依赖
"peerDependencies": {    
  "react": "^16.12.0",
  "react-dom": "^16.12.0",
}
复制代码这样在开发阶段由于没有对应依赖模块,编译器就会报错:
Cannot find module: ‘react’. Make sure this package is installed.
复制代码为了解决开发阶段能使用react这些peerDependencies的问题,一个解决方案是将peerDependencies移动到devDependencies中,另一个就是前面提到的升级npm版本。
如果使用第一种方式,react能够正常安装了,但开发者在这个第三方库编写完后想npm link到宿主应用中进行本地调试时,运行后会报错:

Dan也回复这个issue。事实上,npm link后会存在两个react模块引用,被react「检测」到则会报错,npm link后的结构:
host-app
  └─┬ node_modules
    ├── react
    ├── react-dom
    └── plugin
          └─┬node_modules
            ├── react
            └── react-dom
复制代码解决多个react模块拷贝问题的思路是让项目里存在一个react模块引用,有两种解决方案
- 
使用 webpack alias// 凡是遇到require react时都指向宿主应用下node_modules/react resolve: { alias: { react: require.resolve('react') } } 复制代码
- 
使用 npm link让宿主应用和插件的react保持一致// plugin cd node_modules/react npm link // host app npm link react 复制代码
External Dependencies
构建工具像webpack、rollup提供了External Dependencies,它并没有在npm文档中声明,这是构建工具提供的功能,我们只需要这样声明External Dependencies:
externals: ['react', 'react-dom']
复制代码External Dependencies不会被打包器打包进生产文件中,同时打包完的这个库期望最终的产品应用能提供这些依赖,看起来External Dependencies与peerDependencies类似,不同的是peerDependencies能在npm install找不到依赖时抛出警告。
























![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)
