You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PostProcessBuilder仅触发一次的原因及持续运行解决方案

问题:PostProcessBuilder仅首次构建时触发,无法随主Builder每次运行

我的实现代码

1. MoveBuilder 类实现

class MoveBuilder extends PostProcessBuilder {

  @override
  Iterable<String> get inputExtensions => ['.g.dart'];

  MoveModelBuilder() ;

  @override
  Future<void> build(PostProcessBuildStep buildStep) async {
    log.info('MOVE THE FILE');
  }
}

2. 顶层工厂函数

PostProcessBuilder moveSomething(BuilderOptions options) {
  return MoveModelBuilder();
}

3. 生成器包的 build.yaml 配置

builders:
  my_builder:
    import: "package:my_package/src/builders/builders.dart"
    builder_factories: ["buildSomething"]
    build_extensions: {'.dart': ['.g.dart']}
    auto_apply: none
    build_to: source
    applies_builders:
      - my_package|move_builder

post_process_builders:
  move_builder:
    import: "package:my_package/src/builders/builders.dart"
    builder_factory: moveSomething

4. 使用生成器的外部包 build.yaml 配置

targets:
  $default:
    builders:
      my_package|my_builder:
        enabled: true
        generate_for:
          - lib/*/input_folder/*.dart
      my_package|move_builder:
        enabled: true
        generate_for:
          - lib/*/relative_output_folder/*.g.dart

问题现象

仅首次运行build_runner命令时MoveBuilder会被触发,且仅在出现「缓存资产图已重置」的警告后才会触发。需要让它每次在主Builder运行完成后都执行。


解决方案

核心问题分析

  1. 缓存机制限制:PostProcessBuilder默认仅在输入资产(这里是.g.dart文件)内容变更时触发。主Builder生成.g.dart后,若内容无变化,构建缓存会判定资产未修改,不会触发后续的PostProcessBuilder。
  2. 配置冲突:外部包中直接启用move_builder并指定generate_for为目标路径的.g.dart,但主Builder生成的文件实际在输入路径下,导致PostProcessBuilder无法正确追踪资产的生成事件。

修复步骤

  1. 移除外部包中对move_builder的单独配置
    主Builder已经通过applies_builders声明了对move_builder的依赖,外部包无需重复启用,否则会干扰构建依赖链。修改外部包的build.yaml:

    targets:
      $default:
        builders:
          my_package|my_builder:
            enabled: true
            generate_for:
              - lib/*/input_folder/*.dart
    
  2. 强制触发PostProcessBuilder(临时方案)
    如果必须使用PostProcessBuilder,可以在build方法中标记输入资产为已修改,强制构建系统下次运行时重新处理:

    @override
    Future<void> build(PostProcessBuildStep buildStep) async {
      log.info('MOVE THE FILE');
      // 标记资产为已修改,打破缓存
      await buildStep.canRead(buildStep.inputId);
      buildStep.inputId.changeState(AssetState.modified);
    }
    

    注意:这种方式会跳过缓存优化,可能降低构建效率。


最佳实践:不要用PostProcessBuilder移动文件

Dart Build系统官方推荐通过构建扩展的捕获组直接指定输出路径,替代事后移动文件的操作,这是更符合构建系统设计的方案。

实现方式

修改主Builder的build_extensions配置,使用捕获组将生成文件直接输出到目标路径:

builders:
  my_builder:
    # ... 其他配置
    build_extensions: {'lib/*/input_folder/*.dart': ['lib/$1/relative_output_folder/*.g.dart']}

这样主Builder处理lib/x/input_folder/a.dart时,会直接将生成的.g.dart文件输出到lib/x/relative_output_folder/a.g.dart,完全不需要PostProcessBuilder介入。


内容的提问来源于stack exchange,提问作者anonymous-dev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 10:10:58