Skip to content

Guidance on how to create our own Builder #745

Description

@Hinageshi

Hi, I am writing this seeking for help, since it's quite complicated to find resources on the best way to create Builders 🙂

For our project, we created our own Builder for a specific task. From an input file containing annotated elements, we'd like to obtain a .rpc.dart generated file. Then, we want to apply the retrofit builder on this generated file, to obtain the output, a generated file with .g.dart extension.

For this, we created rpc_generator using source_gen. The build.yaml file looks like this:

builders:
  rpc_generator:
    import: "package:rpc_generator/rpc_generator.dart"
    builder_factories: ["rpcBuilder"]
    build_extensions: { ".dart": [".rpc.dart"] }
    auto_apply: dependents
    build_to: source
    runs_before: ["retrofit_generator"]
    applies_builders: ["retrofit_generator"]

rpc_generator.dart contains the following:
Builder rpcBuilder(BuilderOptions options) => generatorFactoryBuilder(options);

And finally, the builder and generator themselves:

Builder generatorFactoryBuilder(BuilderOptions _) {
  return PartBuilder(
    [const RpcGenerator()],
    '.rpc.dart',
    header: '''
    // coverage:ignore-file
    // GENERATED CODE - DO NOT MODIFY BY HAND
        ''',
  );
}

class RpcGenerator extends Generator {
  const RpcGenerator();

  @override
  Future<String> generate(LibraryReader library, BuildStep buildStep) async {
     ...
  }
}

In local, we have this build.yaml file to call our Builder on our files:

global_options:
  freezed:
    runs_before:
      - json_serializable
  json_serializable:
    runs_before:
      - retrofit_generator
      - rpc_generator

targets:
  $default:
    builders:
      ...
      rpc_generator:rpcBuilder:
        generate_for:
          - lib/api/rpc/*.api.dart;
          - lib/api/*.api.dart

My questions are the following:

  1. We used a PartBuilder because we have to keep both outputs from our Builder and retrofit builder. But is it possible to do better for this task? Like have a SharedPartBuilder that first generate a .g.dart containing our generated code, then run retrofit builder on this generated code and combine both outputs in a single .g.dart file ?
  2. When launching dart run build_runner build --delete-conflicting-outputs in local, a warning appears: Warning: Configuring `rpc_generator:rpcBuilder` in target `data:data` but this is not a known Builder. Yet, our files are generating correctly. However, when our CI launches the same command through GitHub Actions, the files are not generated. I do not understand why this warning is triggered and why the build_runner behavior changes from local to remote ?
  3. In our local build.yaml file, we HAVE to call the builder like this: rpc_generator:rpcBuilder:, otherwise the files are not generated if we only put rpc_generator:. From what I understood, if the builder has the same name as its package, we should be able to call rpc_generator: directly without having to specify the builder factory. Do you have an idea why this is happening?

Thanks in advance for your help 🙂 I can provide more details if needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions