Open dcharkes opened 3 weeks ago
Summary: This issue proposes a standardized way to generate code in Dart packages without requiring user intervention. It aims to address limitations of existing solutions like macros and build_runner
, which either lack flexibility or require manual steps. The goal is to automatically run code generators before publishing, after dependency changes, and before analysis, ensuring generated code is up-to-date and consistent.
Another option would be to include build_runner
in the SDK somehow, solving the issue with package:build_runner requires users to do a manual extra steps
. This might run against the macro
s efforts though.
TL;DR: Either run automatically or check in the code, not both.
Macro's can only take Dart code as input and output.
That's an assumption for the input. We don't currently let macros access the file system, but we could. If we did, then you could pass the URI of a file as an argument in the macro application, have the macro load the file (in a way that can be cached in the macro server between phases) and then it can generate code from that data too.
The alternative is to take the entire file, convert it to a Dart constant value, and have that in the macro annotation, which is just a two-step code generation where you generate the macro application code. (I'd totally do that.)
Assumptions:
- The generated files are checked in.
That's a very strong warning signal for me. Never check in auto-generated code.
It's OK to have a generator that you run manually to generate some code, and then you check in the generated code. It's a code updater then, not a code generator. When people check out the code, the code they see is the code they get, nobody will overwrite it with something else. It's stable.
It's also OK to have an automatically run generator, which generates files on demand, before they are needed. Those files should not be checked in. If the code that is checked in can be changed without you asking for it, then you can't trust the repository code anyway. It's better to have no code then.
If an automatically run generator is for Dart code, macros should be perfect for that. That's exactly the job macros are designed for, as long as they can get the data needed to generate the code. It's automatically generated code, guaranteed up-to-date, that you can still inspect, because every tool that processes Dart programs are aware of macros. It avoids any need ever storing the code, and checking it in.
Now, for non-Dart output, macros are obviously not the answer. There will need to be some code to generate such files. And a standard for where to place them. (Should the be in lib/
if another package depends on them?)
If files are checked in, I'd be more comfortable with a non-automatically run step, where you have to run dart generate
to create/update the generated files. There is no need for someone just depending on a Pub packge to run dart generate
for that package, if all generated files are checked in anyway.
Code generators can be heavy to run (definitely longer-running than macros).
That doesn't compute for me. Macros are code generators. You may have some heavy use-cases in mind, but whatever framework we create here should be able to handle both small and big tasks. And so should macros.
We'd like a standardized way to generate code in Dart packages that does not require a user step.
package:build_runner
requires users to do a manual extra stepsIn some
hook/generate.dart
this would be apackage:build_runner
equivalent, but it would be aware of the Dart/Flutter SDK and have no race conditions between saving files and runningdart
andflutter
commands (see below).In https://github.com/dart-lang/sdk/issues/54334, we've discussed multiple aspects w.r.t. code generators. Today we discussed some more requirements offline:
pub publish
to ensure no files are outdated.pub get
, beforedart analyze
. (Only needed if the generated code is not checked in.)Assumptions:
Some open questions:
hook/build.dart
? Or a mode for the build hook?generate
hook is finished before running the build hook? (E.g. generate is run on-save of its dependencies, likebuild_runner
. But then if you hot-restart in Flutter, you want that on-save action to be fully done first.)Use cases:
Background knowledge:
build.rs
enables generating of Rust files. https://doc.rust-lang.org/cargo/reference/build-script-examples.html#code-generationThanks @mosuem @HosseinYousefi @mkustermann @liamappelbe for the discussion! Please elaborate on things I left out.