一、为啥要搞团队专属的Dart lint规范
做开发的都知道,代码写得好不好,除了功能对不对,还有个很重要的点是“风格统一”。尤其是团队人多的时候,你写的变量名用驼峰,我用下划线,他还加个拼音,新人接手项目光认变量名就得花半天;再比如有人喜欢把一行代码写得老长,有人每个条件判断都加注释,这些乱七八糟的风格凑一起,代码库就跟“百家饭”似的,维护起来巨费劲。
之前大家可能用过Dart自带的dart analyze,它能查语法错误、简单的风格问题,但自带的规则太通用了,满足不了团队的特殊要求。比如我们团队要求所有和支付相关的函数必须加注释说明风险等级,或者所有自定义组件的构造函数必须传key,自带规则就管不了。这时候就需要定制专属的lint规则,还要自动检查,不然靠人review太费时间,还容易漏。
二、用custom_lint搞定制规则的核心步骤
custom_lint是专门给Dart/Flutter做定制lint的工具,相当于给我们开了个“规则自定义权限”,想查啥就查啥。整个流程分三步:先搭基础项目,再写具体规则,最后测试规则。
2.1 先搭custom_lint的基础项目
首先得准备两个项目:一个是“规则项目”(用来写我们的定制规则),一个是“测试项目”(用来验证规则好不好用)。
先建规则项目,用下面的命令:
# 新建一个叫team_lint的规则项目,选package类型
dart create -t package team_lint
cd team_lint
然后给这个项目加custom_lint的依赖,打开pubspec.yaml,把依赖改成下面这样:
name: team_lint
description: 团队专属的Dart lint规则
version: 1.0.0
environment:
sdk: '>=3.0.0 <4.0.0'
dependencies:
analyzer: ^6.0.0 # 用来分析代码结构的工具
custom_lint: ^0.5.0 # 核心的定制lint工具
source_span: ^1.10.0 # 用来定位代码问题的位置
dev_dependencies:
test: ^1.24.0
改完后运行dart pub get装依赖。
接下来要把规则项目变成custom_lint能识别的插件,打开lib/team_lint.dart,改成:
// 告诉custom_lint,这个项目的规则都从这里加载
import 'package:custom_lint_builder/custom_lint_builder.dart';
import 'src/rules/payment_function_comment.dart'; // 后面要写的规则文件
PluginBase createPlugin() => _TeamLintPlugin();
class _TeamLintPlugin extends PluginBase {
@override
List<LintRule> getLintRules(CustomLintConfigs configs) {
// 把我们写的规则加进来,后面加新规则就往这个列表里添
return [
PaymentFunctionCommentRule(),
];
}
}
然后在lib/src下新建rules文件夹,再建payment_function_comment.dart,这就是我们具体规则的文件。
2.2 写第一个定制规则:支付函数必须加风险注释
我们团队的要求是:所有函数名以“pay”开头的(比如payOrder、payWithAlipay),必须加文档注释,而且注释里必须有“风险等级:低/中/高”的字样,不然就报警告。
先写这个规则的代码,打开lib/src/rules/payment_function_comment.dart:
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:custom_lint_builder/custom_lint_builder.dart';
// 规则必须继承自LintRule
class PaymentFunctionCommentRule extends LintRule {
// 规则的唯一ID,必须唯一,用来区分不同规则
static const String ruleId = 'payment_function_comment';
// 规则的配置:比如错误等级、显示的标题、详细说明
static const LintCode code = LintCode(
ruleId,
'支付函数必须添加风险等级注释', // 显示给开发者的错误标题
problemMessage: '函数名以"pay"开头的支付函数,必须添加包含"风险等级:X"的文档注释', // 详细错误说明
correctionMessage: '请在函数上方添加文档注释,格式为/// 支付XX:风险等级:X', // 给开发者的修正提示
);
// 初始化规则
PaymentFunctionCommentRule() : super(code: code);
// 核心逻辑:遍历代码,找符合条件的函数
@override
void run(
CustomLintResolver resolver,
ChangeReporter reporter,
CustomLintContext context,
) {
// 注册回调:当解析完一个函数声明时,执行检查逻辑
context.registry.addFunctionDeclaration((node) {
// 1. 先判断函数名是不是以pay开头(忽略大小写,比如PayOrder也能匹配)
final functionName = node.name.lexeme.toLowerCase();
if (!functionName.startsWith('pay')) return;
// 2. 再判断有没有文档注释,以及注释里有没有“风险等级:”
final docComment = node.documentationComment;
if (docComment == null) {
// 没有注释,直接报错误
_reportError(reporter, node);
return;
}
// 把所有注释拼起来,检查有没有“风险等级:”
final commentText = docComment.tokens.join(' ');
if (!commentText.contains('风险等级:')) {
// 有注释但没风险等级,报错误
_reportError(reporter, node);
}
});
}
// 封装报错误的逻辑,避免重复代码
void _reportError(ChangeReporter reporter, FunctionDeclaration node) {
reporter.createChangeBuilder(
message: code.problemMessage,
priority: LintCodePriority.error,
).addDartFileEdit((builder) {
builder.addSimpleInsertion(
node.offset, // 错误位置的起始位置
'/// 支付${node.name.lexeme}:风险等级:\n', // 给开发者的自动补全提示
);
});
}
}
这个规则的逻辑很简单:先找所有函数,过滤出名字以pay开头的,然后检查有没有注释、注释里有没有要求的内容,不符合就报错,还能自动补个模板注释。
2.3 测试规则好不好用
规则写完得验证,我们需要一个测试项目。回到规则项目的根目录,新建一个叫test_project的文件夹:
dart create test_project
cd test_project
然后打开test_project的pubspec.yaml,加规则项目的依赖(因为我们的规则项目还没发布到pub,所以用本地路径):
name: test_project
description: 测试定制lint规则的项目
version: 1.0.0
environment:
sdk: '>=3.0.0 <4.0.0'
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
custom_lint: ^0.5.0
# 引入本地的规则项目,路径要对
team_lint:
path: ../team_lint
改完运行dart pub get装依赖。
接下来打开test_project的lib/main.dart,写几个测试用的函数:
// 正确的函数:有注释,有风险等级
/// 支付订单:风险等级:中
void payOrder() {}
// 错误的函数:没有注释
void payWithAlipay() {}
// 错误的函数:有注释但没风险等级
/// 支付会员费
void payVip() {}
// 非支付函数:不检查
void getUserInfo() {}
然后运行custom_lint的检查命令:
dart run custom_lint
正常会输出两个错误,对应payWithAlipay和payVip这两个不符合要求的函数,说明规则生效了。
三、把规则集成到CI里,实现自动检查
规则写好、测试通过后,还得把它加到CI(持续集成)里,这样每次有人提交代码,CI就会自动跑检查,不符合要求的代码不让合并,彻底杜绝“百家饭”代码。
3.1 选CI工具:用GitHub Actions举例
现在大部分项目都用GitHub托管,所以我们用GitHub Actions来做CI,其他CI工具(比如GitLab CI、Jenkins)逻辑差不多,只是配置文件格式不一样。
先在项目根目录新建.github/workflows文件夹,再新建lint.yml文件,内容如下:
name: Dart Lint Check # CI任务的名字,GitHub上显示的
on:
# 触发条件:每次有人提交代码到main分支,或者提PR到main分支时
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
lint:
runs-on: ubuntu-latest # 用Ubuntu系统跑任务
steps:
# 第一步:拉取最新的代码
- name: Checkout code
uses: actions/checkout@v4
# 第二步:安装Dart环境,指定版本和项目的SDK版本一致
- name: Set up Dart
uses: dart-lang/setup-dart@v1
with:
sdk: '3.0.0' # 要和项目的sdk版本一致
# 第三步:安装项目依赖
- name: Install dependencies
run: dart pub get
# 第四步:跑定制的lint检查
- name: Run custom lint
run: dart run custom_lint
这个配置的逻辑很简单:每次有代码提交或者PR,就拉代码、装依赖、跑lint检查,如果检查失败,CI就会标红,阻止代码合并。
3.2 注意事项:避免CI报错的坑
- 路径问题:如果规则项目和测试项目不在同一个仓库,不能用本地路径引入,得把规则项目发布到pub.dev,或者用git路径引入,比如:
dev_dependencies:
team_lint:
git:
url: https://github.com/xxx/team_lint.git
ref: main # 用main分支的代码
- 版本问题:所有依赖的版本(比如analyzer、custom_lint)要和项目的Dart SDK版本兼容,不然会报依赖冲突。
- 规则优先级:如果有多个规则,要设置优先级,比如把严重的错误设为error,警告设为warning,避免无关的警告干扰检查。
四、定制规则的应用场景、优缺点和注意事项
4.1 应用场景
除了我们举的支付函数加注释的例子,定制规则还能解决很多团队的特殊问题:
- 所有自定义组件的构造函数必须传key(Flutter项目常用,避免组件状态混乱);
- 所有接口请求的函数必须加超时时间的参数;
- 所有枚举类必须有对应的字符串转枚举的方法;
- 禁止用某些过时的函数(比如自己团队废弃的旧支付接口)。
4.2 优缺点
优点:
- 统一代码风格:彻底解决团队代码风格不一致的问题,新人接手快,维护成本低;
- 提前发现问题:能检查出静态分析工具查不到的问题,比如团队的特殊要求,减少review的压力;
- 自动执行:集成到CI后,不用人盯着,代码提交就自动检查,避免漏查。
缺点:
- 有学习成本:要写规则得懂analyzer的代码结构,刚开始写规则可能会觉得难;
- 维护成本:规则多了之后,每次Dart SDK升级,可能要更新analyzer、custom_lint的版本,不然会报错;
- 不能太复杂:规则太复杂的话,跑检查的时间会变长,影响CI的速度,所以规则要尽量简单。
4.3 注意事项
- 规则不要太多:只加团队真正需要的规则,太多规则会让开发者觉得麻烦,反而产生抵触情绪;
- 规则要灵活:可以给规则加配置,比如有些函数可以豁免检查(比如测试用的函数);
- 及时更新:Dart SDK升级后,要及时更新规则的依赖,避免规则失效;
- 给开发者反馈:规则报错时,要给明确的修正提示,比如我们写的自动补全注释,让开发者知道怎么改。
五、总结
搞团队专属的Dart lint规范,本质上是用工具代替人来管理代码质量,既统一了风格,又减少了维护成本。整个流程其实不复杂:先搭custom_lint的基础项目,再写符合团队要求的规则,测试通过后集成到CI里自动检查。刚开始可能会觉得写规则有点难,但只要多写几个例子,熟悉了analyzer的逻辑,就能轻松搞定。
最后要提醒的是,规则不是越多越好,要贴合团队的实际需求,比如小团队可能只需要几个核心规则,大团队可以多加点,但也要注意不要给开发者增加太多负担。只要规则合适,就能让团队的代码质量上一个台阶,大家写代码也更省心。
评论
围绕“大规模Dart团队lint规范:借助custom_lint定制规则并集成CI检查”参与讨论