打包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就会有警告来提醒使用者去解决版本冲突问题。