大家好,我是若川。
     
     我持续组织了近一年的
     
      源码共读活动
     
     ,感兴趣的可以
     
      点此扫码加我微信 lxchuan12
     
     参与,每周大家一起学习200行左右的源码,共同进步。同时极力推荐订阅我写的
     
      《学习源码整体架构系列》
     
     包含20余篇源码文章。
     
      历史面试系列
     
     。另外:目前建有
     
      江西|湖南|湖北|河南
     
     籍前端群,可加我微信进群。
     
      欢迎星标我的公众号~不错过推文~
     
    
现代的前端开发、Node.js 后端开发中 NPM 包管理是最基础也是最关键的一部分,本文将从一个问题开始,阐述 NPM 版本控制的工作原理,我相信这是每一个使用了 NPM 的开发人员都应该熟悉的知识。
     一个依赖安装失败示例
    
事情的经过是前一天测试还一切正常,第二天部署时却提示 yarn 安装依赖失败,下面是本地复现的结果,如下图所示:
    
    
     一个明显的提示是
     
      bson@5.0.0
     
     这个依赖不再支持
     
      Node.js 14.20.1
     
     以下版本,但是项目的
     
      dependencies
     
     中也没有指定这个包啊,了解 MongoDB 的同学应该知道
     
      bson
     
     是
     
      Mongo
     
     实现的一个类
     
      JSON
     
     的二进制存储格式。
    
     为了一探究竟,执行
     
      yarn --ignore-engines
     
     先忽略这个引擎检测,看下
     
      yarn.lock
     
     文件中 bson 的依赖关系。
    
     
      mongoose@^5.3.0
     
     是项目中的依赖,实际安装后使用的版本为
     
      5.13.5
     
     ,之后又依赖了
     
      @types/mongodb
     
     ,问题来了,这里竟然使用了
     
      @types/bson: *
     
     要知道在 NPM 的版本号规则里
     
      *
     
     号是不会锁定版本的,每次都会升级为最新版本,也就是最后的
     
      bson: 5.0.0
     
     。
     
     
     查了下
     
      bson
     
     这个库的 CHANGELOG 发现其在
     
      2023-01-31
     
     号发布了
     
      5.0.0
     
     ,要求 Node.js 版本必须大于 14.20.1,上面报错显然当前版本不满足。
    
     
      库的版本升级很正常,了解 NPM 版本号规则的同学应该知道
      
       “bson: 5.0.0 ”
      
      这是一个大版本,会存在不向前兼容的情况,这里的问题在于
      
       @types/mongodb
      
      直接使用了
      
       @types/bson: *
      
      ,每次安装都会升级到最新,是有点不讲 “码德”,这里是个坑
     
     ,NPM 上查了 @types/mongodb 这个包,发现已经被废弃了,如下图所示:
    
    
     
      
       mongoose
      
      这个包的影响版本为:
      
       mongoose 5.11 ~ 5.13.15
      
      。
     
    
     这里先抛出一个问题:“为什么安装时使用的
     
      mongoose@^5.3.0
     
     安装成功后却变成了
     
      5.13.15
     
     ”?
    
     NPM 的语义版本控制
    
     在发布 NPM 模块新版本时,建议遵循 “语义版本控制” 考虑使用这样的版本号
     
      x.y.z
     
     控制,如下所示:
     
     版本号规则:
    
- 
主版本:做了不兼容的 API 修改,不会向前兼容,一般也称为大版本,当项目依赖需要升级到大版本时需要注意。 
- 
次版本:通常是做了向前兼容的新功能增加,一般也称为小版本。 
- 
补丁版本:修复现有的一些错误,也是向前兼容的。 
在发布 NPM 包时建议从 1.0.0 开始,例如:
- 
1.0.0:新产品首次发布。 
- 
1.0.1:向前兼容的补丁版本,修改第 3 位数。 
- 
1.1.0:向前兼容增加新特性,增加中间数字,将最后一位置为 0。 
- 
2.0.0:不向前兼容的更新,增加第一位数字,将第二、三位数置为 0。 
语义化版本号的几种表示方法:
- 
 ^1.1.2
 
 :
 
 ^
 
 是 NPM 安装后的默认符号,保持高版本不升级,次版本、补丁版本升级到最新,例如:
 
 ^1.1.2
 
 等价于
 
 1.1.2 >= ^1.1.2 < 2.0.0
 
 。
- 
 ~1.1.3
 
 :波浪符
 
 ~
 
 只会升级补丁版本,例如:
 
 ~1.1.3
 
 等价于
 
 1.1.3 >= ~1.1.3 <1.2.0
 
 。
- 
 1.1.3
 
 :不加任何符号表示锁定了这个版本,不会进行任何升级。
- 
 * 或 ""
 
 :
 
 *
 
 号或者空字符
 
 ""
 
 ,不会锁定版本,每次都会升级到最新版本,前面提的问题就是这个导致的。
- 
 1.0.0-alpha.1
 
 :使用 alpha、rc 等标识的表示该版本是一个预发布版本,该版本可能无法满足预期的兼容性需求,正式环境不要用。
- 
一个非语义话版本号的示例 
 
 v1.0.0
 
 :在一些版本控制的系统中通常用 v 表示版本号,例如
 
 git tag v1.0.0
 
 ,但它并不是语义化版本号。
     了解了语义化版本号规则后,应该要知道上面提出的一个问题:“为什么安装时使用的
     
      mongoose@^5.3.0
     
     安装成功后却变成了
     
      5.13.15
     
     ”,因为版本号前加
     
      ^
     
     符号,它表示的是第一位保持不变、最后两位升级到最新。
    
     依赖锁定 – 解决版本不一致问题
    
     考虑一个问题,项目第一次添加一个模块的依赖是
     
      ^1.2.3
     
     ,过了两周另一个同事需要修这个项目,此时依赖已经更新到
     
      1.3.0
     
     他在重新安装后就会得到最新的版本,这会带来一个问题,每个人得到依赖版本不一致,该如何确保团队成员的依赖版本都是一致呢?
    
     
      解决依赖版本不一致的问题一种方法是 “固定依赖版本”
     
     ,但在实际做法中这种很少见,大多数时候没有意识到一个问题 “安全修复”,通过版本号前加 ^ 或 ~ 符号我们可以得到补丁版本错误修复、向前兼容的小版本新功能。
    
     解决依赖版本不一致的另一种方法是通过 lock 文件(
     
      NPM 中的 package-lock.json
     
     或
     
      yarn 中的 yarn.lock
     
     )来解决同一个项目团队成员之间依赖版本不一致的问题,在使用 npm 或 yarn 安装之前会先检查 lock 文件上的版本,并来安装它们,有必要将 lock 文件推送至 git 仓库。
    
     如果需要将依赖项更新到指定范围的最新版本,只需要执行
     
      npm update
     
     命令,该命令会遵循语义化版本控制对依赖进行升级,同时也会更新 lock 文件。
     
    
– 这是底线 –
 
