在《如何做好 Code Review》 中我论述过代码审查对于保证代码品质的重要性,最近开始采用Git Hooks 的方式为Flutter 项目增加提交前的强制自我审查。这样做的好处在于将机械化检查交给电脑,把思考的部分留给大脑。
我认为代码提交前需要做的最基本检查包括格式和代码规范。前者交给Prettier ,后者由Analyze 负责。
Lefthook 我采用Lefthook 实现 Git 钩子,如果你有更好的选择,欢迎推荐分享。
1 2 brew install lefthook && lefthook install
安装 Lefthook 后,在项目根目录下运行lefthook install
命令来生成lefthook.yml
文件,并在其中的pre-commit > commands
节点下添加两项配置:
1 2 3 4 5 prettier: glob: "*.dart" run: dart format {staged_files } && git add {staged_files } linter: run: dart analyze
Analyze flutter analyze
通过flutter_lints 插件对Dart 代码进行静态语言检查,检查规则配置在analysis_options.yaml
文件中。但是打开该文件可以看到,Flutter 并没有为我们配置任何默认规则。我把我正在采用的规则配置放在文末,欢迎酌情采纳。
接下来我们可以测试一下配置能否正常工作。比如,将main()
替换为:
1 2 3 4 5 void main() { const title= 'Flutter' ; runApp(const MyApp());} aa() {}
然后运行命令:
1 git add .&&git commit -m 'Commit for analysis.'
接下来你会发现,Prettier 将代码格式化为:
1 2 3 4 5 6 void main() { const title = 'Flutter' ; runApp(const MyApp()); } aa() {}
但是静态检查没有通过,因为title
变量没有被使用、函数aa
没有返回类型等:
1 2 3 4 5 6 7 8 EXECUTE > linter Analyzing demo_lint_flutter... info • The value of the local variable 'title' isn't used • lib/main.dart:4:9 • unused_local_variable info • The function ' aa' should have a return type but doesn' t • lib/main.dart:8:1 • always_declare_return_types info • Type annotate public APIs • lib/main.dart:8:1 • type_annotate_public_apis 3 issues found. (ran in 2.0s)
强烈建议你在接下来的每一个 Flutter 项目里都坚持这样做,不要提交 Smelling Code。
analysis_options.yaml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 include: package:flutter_lints/flutter.yaml analyzer: strong-mode: implicit-casts: false errors: missing_required_param: warning missing_return: warning todo: ignore linter: rules: always_declare_return_types: true always_require_non_null_named_parameters: true annotate_overrides: true avoid_bool_literals_in_conditional_expressions: true avoid_catching_errors: true avoid_classes_with_only_static_members: true avoid_empty_else: true avoid_escaping_inner_quotes: true avoid_field_initializers_in_const_classes: true avoid_function_literals_in_foreach_calls: true avoid_implementing_value_types: true avoid_init_to_null: true avoid_multiple_declarations_per_line: true avoid_null_checks_in_equality_operators: true avoid_positional_boolean_parameters: true avoid_print: true avoid_private_typedef_functions: true avoid_redundant_argument_values: true avoid_relative_lib_imports: true avoid_return_types_on_setters: true avoid_returning_null_for_future: true avoid_returning_null_for_void: true avoid_setters_without_getters: true avoid_shadowing_type_parameters: true avoid_single_cascade_in_expression_statements: true avoid_type_to_string: true avoid_types_as_parameter_names: true avoid_unnecessary_containers: true avoid_unused_constructor_parameters: true avoid_void_async: true avoid_web_libraries_in_flutter: true await_only_futures: true camel_case_extensions: true camel_case_types: true cancel_subscriptions: true cast_nullable_to_non_nullable: true constant_identifier_names: true control_flow_in_finally: true curly_braces_in_flow_control_structures: true depend_on_referenced_packages: true deprecated_consistency: true empty_catches: true empty_constructor_bodies: true empty_statements: true eol_at_end_of_file: true exhaustive_cases: true file_names: true hash_and_equals: true implementation_imports: true invariant_booleans: true iterable_contains_unrelated_type: true join_return_with_assignment: true leading_newlines_in_multiline_strings: true library_names: true library_prefixes: true list_remove_unrelated_type: true missing_whitespace_between_adjacent_strings: true no_adjacent_strings_in_list: true no_duplicate_case_values: true no_logic_in_create_state: true no_runtimeType_toString: true non_constant_identifier_names: true noop_primitive_operations: true null_check_on_nullable_type_parameter: true null_closures: true overridden_fields: true package_names: true package_prefixed_library_names: true parameter_assignments: true prefer_asserts_in_initializer_lists: true prefer_collection_literals: true prefer_conditional_assignment: true prefer_const_constructors: true prefer_const_constructors_in_immutables: true prefer_const_declarations: true prefer_const_literals_to_create_immutables: true prefer_constructors_over_static_methods: true prefer_contains: true prefer_equal_for_default_values: true prefer_final_fields: true prefer_final_in_for_each: true prefer_final_locals: true prefer_for_elements_to_map_fromIterable: true prefer_function_declarations_over_variables: true prefer_generic_function_type_aliases: true prefer_if_elements_to_conditional_expressions: true prefer_if_null_operators: true prefer_initializing_formals: true prefer_inlined_adds: true prefer_interpolation_to_compose_strings: true prefer_is_empty: true prefer_is_not_empty: true prefer_is_not_operator: true prefer_iterable_whereType: true prefer_null_aware_method_calls: true prefer_spread_collections: true prefer_typing_uninitialized_variables: true prefer_void_to_null: true provide_deprecation_message: true recursive_getters: true require_trailing_commas: true sized_box_for_whitespace: true slash_for_doc_comments: true sort_child_properties_last: true sort_unnamed_constructors_first: true test_types_in_equals: true throw_in_finally: true tighten_type_of_initializing_formals: true type_annotate_public_apis: true type_init_formals: true unnecessary_await_in_return: true unnecessary_brace_in_string_interps: true unnecessary_const: true unnecessary_getters_setters: true unnecessary_new: true unnecessary_null_aware_assignments: true unnecessary_null_checks: true unnecessary_null_in_if_null_operators: true unnecessary_nullable_for_final_variable_declarations: true unnecessary_overrides: true unnecessary_parenthesis: true unnecessary_raw_strings: true unnecessary_statements: true unnecessary_string_escapes: true unnecessary_string_interpolations: true unnecessary_this: true unrelated_type_equality_checks: true unsafe_html: true use_build_context_synchronously: true use_full_hex_values_for_flutter_colors: true use_function_type_syntax_for_parameters: true use_named_constants: true use_late_for_private_fields_and_variables: true use_rethrow_when_possible: true use_setters_to_change_properties: true use_string_buffers: true use_test_throws_matchers: true valid_regexps: true void_checks: true