打包npm模块时经常担心自己模块所依赖的模块与包使用者的其他模块会产生冲突,为理清npm模块间的依赖处理策略,我做了一些实验进行测试,测试环境如下:
node版本:6.2.2
npm版本:3.9.5
两个工程:
dependenciesModule: 第三方模块,依赖react,已上传到npm
dependenciesDemo:dependenciesModule的使用者
结果分为两部分:
1. dependenciesDemo本地未安装任何模块
dependenciesModule列的内容为模块自身package.json设置的字段和react版本
| dependenciesModule | dependenciesDemo | |
|---|---|---|
| ① | dependencies: 15.3.1 |
安装在本地目录下:15.3.1
|
| ② | peerDependencies: 15.3.1 |
本地目录和模块目录下均不安装 |
| ③ | dependencies: 15.3.1 + peerDependencies: 15.3.1 |
安装在本地目录下:15.3.1,peerDependencies被忽略,效果同① |
| ④ | dependencies: 15.0.0 + peerDependencies: 15.3.1 |
安装在本地目录下:15.0.0,版本为dependencies下的版本 |
2. 在dependenciesDemo下已安装react或设置了package.json的dependencies
① 本地安装了react,并且在package.json的dependencies下设置了react
在dependenciesModule内单独安装react,即使dependenciesModule依赖的react版本与本地已安装的react版本相同,但只安装react,react的依赖库不再安装。
② 本地的package.json的dependencies已添加react,版本为15.3.1
无论本地是否实际安装有react模块,都会在dependenciesModule内单独安装react,即使dependencies依赖的react版本同样为15.3.1,仍然只安装react,react的依赖库会安装在本地目录下。
③ 本地安装了react,但没有设置package.json的dependencies
只安装dependenciesModule,本地与模块内均不再安装react
总结
已安装
react15.3.1,再安装react15.0.0,会删除之前安装的react15.3.1,然后重装react15.0.0。npm3在安装包时会采用扁平化处理,包以及包依赖的其他模块将会以同层级的方式安装在包使用者的node_modules下 ,如果版本有冲突,才会采用npm2的嵌套方式安装在各个包下。具体可参考npm v3 Dependency Resolution。在
npm3下,peerDependencies下模块不会自动安装,需要模块使用者在本地目录手动安装,如果没安装会发出警告。npm文档中对peerDependencies的介绍是:
In some cases, you want to express the compatibility of your package with a host tool or library, while not necessarily doing a require of this host. This is usually referred to as a plugin. Notably, your module may be exposing a specific interface, expected and specified by the host documentation.
大概的意思就是:通常是在插件开发的场景下,你的插件需要某些依赖的支持,但是你又没必要去安装,因为插件的宿主会去安装这些依赖,你就可以用peerDependencies去声明一下需要依赖的插件和版本,如果出问题npm就会有警告来提醒使用者去解决版本冲突问题。