思考:
如果你编写了一个包A,依赖另外一个包B,你在编写代码时,包B的版本是2.4.1,你是希望使用你包的人一定要安装包B,并且是2.4.1版本,还是希望他可以安装更高的版本,如果你希望它安装更高的版本,高的什么程度呢?
回顾:版本号规则
版本规范:主版本号.次版本号.补丁版本号
- 主版本号:仅当程序发生了重大变化时才会增长,如新增了重要功能、新增了大量的API、技术架构发生了重大变化
- 次版本号:仅当程序发生了一些小变化时才会增长,如新增了一些小功能、新增了一些辅助型的API
- 补丁版本号:仅当解决了一些 bug 或 进行了一些局部优化时更新,如修复了某个函数的 bug、提升了某个函数的运行效率
有的时候,我们希望:安装我的依赖包的时候,次版本号和补丁版本号是可以有提升的,但是主版本号不能变化;
有的时候,我们又希望:安装我的依赖包的时候,只有补丁版本号可以提升,其他都不能提升;
甚至我们希望依赖包保持固定的版本,尽管这比较少见。
这样一来,就需要在配置文件中描述清楚具体的依赖规则,而不是直接写上版本号那么简单。
这种规则的描述,即语义版本
语义版本的书写规则非常丰富,下面列出了一些常见的书写方式
符号 | 描述 | 示例 | 示例描述 |
---|---|---|---|
> | 大于某个版本 | >1.2.1 | 大于1.2.1版本 |
>= | 大于等于某个版本 | >=1.2.1 | 大于等于1.2.1版本 |
< | 小于某个版本 | <1.2.1 | 小于1.2.1版本 |
<= | 小于等于某个版本 | <=1.2.1 | 小于等于1.2.1版本 |
- | 介于两个版本之间 | 1.2.1 - 1.4.5 | 介于1.2.1和1.4.5之间 |
x | 不固定的版本号 | 1.3.x | 只要保证主版本号是1,次版本号是3即可 |
~ | 补丁版本号可增 | ~1.3.4 | 保证主版本号是1,次版本号是3,补丁版本号大于等于4 |
^ | 此版本和补丁版本可增 | ^1.3.4 | 保证主版本号是1,次版本号可以大于等于3,补丁版本号可以大于等于4 |
* | 最新版本 | * | 始终安装最新版本 |
避免还原的差异:pacakge-lock.json
版本依赖控制,始终是一个两难的问题。
如果允许版本增加,可以让依赖包的bug得以修复(补丁版本号),可以带来一些意外的惊喜(次版本号),但同样可能带来不确定的风险(新的bug)
如果不允许版本增加,可以获得最好的稳定性,但失去了依赖包自我优化的能力
而有的时候情况更加复杂,如果依赖包升级后,依赖也发生了变化,会有更多不确定的情况出现
基于此,npm 在安装包的时候,会自动生成一个package-lock.json文件,该文件记录了安装包时的确切依赖关系
当移植工程时,如果包含 package-lock.json 文件。重新恢复安装时,会按照 package-lock.json 文件中的确切依赖进行安装,最大限度的避免了差异
服务器上要不要这个文件?看项目需求是否需要和开发环境一致。
问题:如果没有package.json文件的话,会安装最新包么?
可以肯定的是,删除了package-lock.json文件后可能不会安装确定的依赖。
[扩展知识]npm的差异版本处理
如果两个包依赖同一个包,版本可以协调的情况下(比如a需要c大于1.0.0就行,B需要c版本为1.1.0),那npm会自动识别安装1.1.0版本的一个c的包,到a和b的同级目录下,供a和b公用。这种做法叫做“flat dependency”。
如果两个包依赖同一个包的不同版本,版本矛盾不可调和:
面对这种情况,在 node_modules 目录中,不会使用扁平的目录结构,而会形成嵌套的目录,
如下图:
即:会在a包和b包下安装各自的包管理器node_modules,然后把各自依赖包的对应版本安装进去。