build 库的使用
2022年10月12日大约 2 分钟
Fair 源码中用到了 build 库,因此,本文主要介绍一下 build 库的使用。
1. build 库的介绍
定义用于创建 Builder 的接口,这是一种在构建系统(pub、bazel、standalone runner)之间兼容的代码生成方式。通常需要配合 build_runner 使用。
2. build 库的使用
2.1 添加 build 库依赖
dependencies:
# ···
build: ^2.3.0
2.2 创建 Builder
代码生成的业务逻辑。通常我们会创建 Builder 的自定义实现。
class CopyBuilder extends Builder {
/// You can only output files that are configured here by suffix substitution.
/// You are not required to output all of these files, but no other builder
/// may declare the same outputs.
@override
Map<String, List<String>> get buildExtensions => const {
......
};
/// This is where you build and output files.
@override
FutureOr<void> build(BuildStep buildStep) async {
......
}
}
介绍一下 Builder 中通常会使用到的工具。
BuildStep
BuildStep 是 Builder 与外部模块交互的方式。通过 BuildStep 可以读/写文件和解析 Dart 源代码。
通常我们会使用 buildStep#readAsString 和 buildStep#writeAsString 读取和写入文件信息而不是直接使用文件系统读取/写入文件。这样不仅可以便于实现增量编译,也不用自己判断适配运行环境。
Resolver
Dart Analyzer的接口,可以解析需要静态分析和/或代码生成的代码。
如果需要解析文件信息,可以使用BuildStep#resolver 。这样可以确保系统中的所有 Builder 共享相同的分析 context,从而在使用多个 Builder 解析时可以大大加快整个系统的速度。
2.3 配置 buildExtensions
buildExtensions 表示从输入扩展名到输出扩展名的映射。
@override
Map<String, List<String>> get buildExtensions => const {
'.dart': ['.dart.copy']
};
2.4 build() 开发
核心业务逻辑开发,比如下面代码,将所有 .dart 的文件拷贝,生成同名但是后缀是 .dart.copy 的文件。
@override
Future<void> build(BuildStep buildStep) async {
// Each `buildStep` has a single input.
var inputId = buildStep.inputId;
// Create a new target `AssetId` based on the old one.
var copy = inputId.addExtension('.copy');
var contents = await buildStep.readAsString(inputId);
// Write out the new asset.
await buildStep.writeAsString(copy, contents);
}
2.5 配置 build.yaml
build.yaml 文件配置如下:
builders:
dart_copy_builder:
import: 'package:dart_copy_helper/builder.dart'
builder_factories: ['dartCpBuilder']
build_extensions: { '.dart': ['.g.dart'] }
auto_apply: root_package
build_to: source
这样,一个简单的使用 build 的 demo 就开发完成了。可以使用如下命令运行。
flutter pub run build_runner build