前几天,Flutter 3.38 & Dart 3.10正式发布,详情参考Flutter3.38 带来了什么。这其中包括了一项新的lint:
remove_deprecations_in_breaking_versions
说人话就是:在主要版本中移除弃用功能。
欢迎关注我的微信公众号:OpenFlutter,谢谢
当你想要在软件包中移除某些 API 时,你不会立即执行,而是会分阶段地逐渐淘汰 。一旦您决定某个功能将在某个时间点移除,您就会在其上加上 @Deprecated 注解:
dart
@Deprecated('This sucks. Use Class2')
class Class1 {}
class Class2 {}
然后,任何使用您软件包的用户,只要使用了被这样注解(即 @Deprecated)的任何功能,就会收到一条 deprecated_member_use 诊断消息。
那么,何时应该移除您之前声明已弃用的 API 呢? 这就是版本号约定发挥作用的时候了。最常见的约定被称为 SemVer(语义化版本控制) ,其定义可在 https://semver.org 查阅。
SemVer 规定,版本号必须包含三个数字:主版本号 (Major).次版本号 (Minor).修订号 (Patch) 。例如,Dart 的当前版本是 3.10.0:
- 3 是主版本号。
- 10 是次版本号。
- 0 是修订号。
当您发布一个新版本,它只修复了错误 ,而没有破坏任何您的软件包用户可能依赖的东西时,您应该增加修订号 (Patch) 。例如,Dart 的上一个版本是 3.9.2,这意味着他们发布了三个 3.9.x 版本,其中最后两个修复了一些错误。
当您发布一个新版本,它增加了新功能 ,但仍然没有破坏任何您的软件包用户可能依赖的东西时,您应该增加次版本号 (Minor) 。例如,从 3.9.2 到 3.10.0,Dart 增加了您的代码可以使用的新功能 ,但保证所有原本可以在 3.9.2 上构建的代码仍然可以在 3.10.0 上构建。
当您发布一个不兼容版本(breaking version) 时,您需要增加主版本号 (Major) 。
Dart 社区采纳了这一标准,但增加了一个额外的限制。尽管标准不保证第一个稳定版本 (1.0.0) 之前的版本之间有任何兼容性,但 Dart 仍然语义化地 处理这些版本:在 1.0.0 之前,次版本号 (minor) 的增加意味着不兼容的变更 (breaking changes) 。这使得我们在宣布稳定版本之前,可以多次发出不兼容版本的信号,以改进我们的软件包。
不兼容版本对您的用户来说简直是地狱,因为除非他们在 pubspec.yaml 中明确允许,否则它不会自动被拉入他们的项目。他们使用的一些软件包可能需要您的新主版本,而其他软件包可能与它不兼容。这就是依赖地狱 (dependency hell) 。您必须避免过于频繁地发布新的主版本。
这就是为什么如果您计划进行不兼容的更改,您通常希望通过一个主版本尽可能多地一次性进行所有破坏性更改,以便您的用户只需适应一次。
因此,如果您发布了一个新的主版本,却忘记移除您原本想移除的东西,那将是非常可惜的。
因此,引入了新的代码风格检查工具(lint)来帮助您解决这个问题。
如果在您的 pubspec.yaml 中,您设置了不兼容的版本号 (x.0.0 或 0.x.0),这个 lint 就会标记出您可能仍然拥有的所有 @Deprecated 注解。
一个有趣的推论是:您不应该在一个不兼容版本中引入新的弃用。如果您这样做,lint 会标记它,您将不得不忽略它。一旦您决定在某处忽略它,您就有可能忽略那些应该被移除但被您遗忘的旧弃用功能所引发的合理警告。
因此,请首先发布一个正常的不兼容版本(其中不包含任何弃用) ,然后在下一个版本 中弃用一些东西。顺便说一句,如果您引入了弃用功能,您应该增加次版本号 (Minor) ,而不仅仅是修订号 (Patch)。
这是因为您软件包的一些用户可能在他们的持续集成(CI)中设置了静态分析,并且有一个规则是不使用任何弃用的代码 。当您弃用某个功能时,这个 CI 就会中断。因此,SemVer 标准中有一项约定,即修订号 (patch) 更新不会中断这种检查。
何时应该使用这个 linter 规则呢? 显然,对于那些构建并交付给用户的常规应用程序来说,它没有任何意义,因为这些用户看不到或使用任何代码。这条规则仅对可发布的软件包(publishable packages)有意义。