source_gen 库的使用

Wuba2022年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
上次编辑于:
贡献者: sunzhe03