依赖管理
node自带依赖管理工具NPM
依赖版本
package.json
项目的依赖保存在根目录的package.json中。
- dependencies
项目运行所需依赖
- devDependencies
仅在项目开发时需要的依赖
- peerDependencies
非项目直接依赖,但项目需要它们配合来运行。表示安装本项目时最好也安装了它们,比如工具类项目的宿主
版本号
依赖的版本用"x.y.z"的格式来表示。
版本号遵循semver规则。x为major版本,表示不兼容的升级;y为minor版本,表示一些向下兼容的新增功能;z为patch版本,表示一些不影响功能的修复和优化。版本号严格递增。
"x.y.z"表示需要的版本号是精确的"x.y.z"。
"^x.y.z"表示允许y和z为最新。npm install时默认保存的是此策略。
"~x.y.z"表示允许z为最新。
">=x.y.z"表示版本大于等于"x.y.z"即可。
多个"与关系"的版本规则可以用空格组合,比如">1.2.3 <1.3.10";"或关系"的版本规则用"||"隔开。
版本锁定
因为版本策略允许使用一个范围内的版本而非精确版本,所以不同环境下的依赖可能会有所不同,也会因此带来一些问题。
NPM5之后,额外使用了package-lock.json来指明依赖的具体版本,该文件会在npm install时自动生成。
在项目里有package-lock.json的情况下,执行npm install分两种情况:
package.json里的依赖和package-lock.json里的都对得上,那么直接使用package-lock.json里的精确版本来安装依赖。
package.json里的某些依赖有更新,并且和package-lock.json里的版本对不上了,那么会根据package.json指定的这个版本策略来安装依赖,并且将当前安装的具体版本自动更新到package-lock.json的对应字段中。
另外,package-lock.json里的dependencies树结构是和node_modules里的文件结构一一对应的。
冗余问题
对于项目里重复的依赖,直接依赖是放在node_modules顶层的,所以多个直接依赖指向的都是同一份依赖。
间接依赖默认被安装到直接依赖各自的子目录下,但此时会有冗余问题。比如直接依赖A和直接依赖B,它们都依赖了X,X即为项目的间接依赖。如果在A和B中各自安装一份X,则多了一份冗余的X。
对于间接依赖的冗余,NPM采取了优化策略。如果发现这种重复的依赖X,就把这个X提取到顶层,因为寻找依赖时自动向上递归查找,所以A和B可在顶层拿到这个X,这样就不会有多余的X。
但此策略下还是会有冗余问题。比如上面的情况中,A和B依赖的X为版本X1,又有一个C,它也依赖了X,但版本是与X1不兼容的X2,那么C就无法使用顶层的X1,此时C会在自己的目录下安装X2。如果后面又有一个D也依赖了X2,那么D也会在自己的目录下安装一份X2。此时项目里还是会有一份冗余的X2。
相比go的依赖管理,go mod安装的依赖是目录名带了版本号平铺开在顶层,所以不管怎样同一版本的依赖项目里只会有一份。似乎这样的设计更加合理。