source_gen 库的使用
2022年10月12日大约 2 分钟
Fair 源码中用到了 source_gen 库,因此,本文主要介绍一下 source_gen 库的使用。
1. source_gen 库的介绍
source_gen 是一个用于 Dart 代码自动生成的工具库和开发框架。相较于 build 库,source_gen 提供更易于使用的 API 和工具。
在 Fair 源码中,Fair DSL 的生成使用了 source_gen。
2. source_gen 库的使用
2.1 添加 source_gen 依赖
dependencies:
  source_gen: ^1.2.2
2.2 创建注解和使用
下面以 Fair 中的使用为例,首先创建了注解 - FairPatch。
/// Annotation for Fair compiler, this indicate the top Widget need to generate as bundle resource
class FairPatch {
  /// Optional,Set the module for the currently generated bundle.
  /// bundle files in the same module can be downloaded as a set of resources.
  final String module;
  const FairPatch({this.module = 'lib'});
}
然后使用 FairPatch。
@FairPatch()
class IfEqualBoolPage extends StatefulWidget {
  var fairProps;
  IfEqualBoolPage(dynamic data) {
    fairProps = data;
  }
  @override
  State<StatefulWidget> createState() {
    return _State();
  }
}
2.3 创建 Generator
class BundleGenerator extends GeneratorForAnnotation<FairPatch>
    with FairCompiler {
  @override
  Future<String?> generateForAnnotatedElement(
      Element element, ConstantReader annotation, BuildStep buildStep) async {
    
    ......
    /// Get the value of the module parameter in the FairPatch annotation.
    /// If module is not set, or the value of module is an empty string, the default value is 'lib'
    var module = annotation.peek('module');
    
    ......
    final tmp = await temp;
    tmp.writeAsBytesSync(await buildStep.readAsBytes(buildStep.inputId));
    var r = await compile(buildStep, ['-f', tmp.absolute.path]);
    tmp.deleteSync();
    ......
    
    return r.data;
  }
}
根据注解 FairPatch 过滤 Dart 源代码,并且可以解析获取 FairPatch 中设置的数据。调用 compile 生成 Fair DSL。
2.4 创建 Builder
Generator 的执行需要 Builder 来触发。创建 Builder 如下:
Builder build(BuilderOptions options) {
  return BundleBuilder(BundleGenerator(), formatOutput: JsonFormatter().format);
}
2.5 创建 build.yaml
builders:
  fairc:
    import: "package:fair_compiler/src/builder.dart"
    builder_factories: ["build", "bind"]
    build_extensions: {".dart": [".bundle.json", ".binding", ".fair.ignore"]}
    auto_apply: root_package
    build_to: cache
    defaults:
      generate_for:
        - lib/**
    applies_builders: [":archive"]
    runs_before: [":archive"]
其中,
- import 用于导入返回 Builder 的方法所在包
 - builder_factories 填写的是返回 Builder 的方法名
 - build_extensions 指定输入扩展名到输出扩展名的映射
 - auto_apply 指定 builder 作用域,可选值:(可选,默认为 none) 
- "none":除非手动配置,否则不要应用此 Builder
 - "dependents":将此Builder应用于包,直接依赖于公开构建器的包
 - "all_packages":将此 Builder 应用于传递依赖关系图中的所有包
 - "root_package":仅将此 Builder 应用于顶级包
 
 - build_to 指定输出位置,(可选,默认为 cache) 
- "source":输出到其主要输入的源码树上
 - "cache":输出到隐藏的构建缓存上
 
 - required_inputs:指定一个或一系列文件扩展名,表示在任何可能产生该类型输出的 Builder 之后运行(可选)
 - runs_before:在指定的 Builder 之前运行
 
2.6 运行 Builder
通常 source_gen 会结合 build_runner 使用,执行如下命令即可:
flutter pub run build_runner build
