Welcome to the future of Flutter development! Imagine a world where the tedious task of writing boilerplate code is a thing of the past. Say hello to Dart Macros – your new secret weapon for supercharging productivity. These powerful runtime code generation tools work their magic behind the scenes, seamlessly reducing boilerplate and eliminating the need for cumbersome secondary tools. With Flutter macros, you can focus on crafting beautiful, high-performance apps while the macros handle the repetitive tasks, making your development process faster and more efficient than ever before. Get ready to unlock a new level of coding freedom and efficiency with Flutter macros!
A Dart macro is a customisable code snippet that takes other code as input and processes it in real-time to create, modify, or add new elements. Macros offer a reusable way to handle repetitive tasks and patterns, especially when dealing with the need to iterate over the fields of a class. Right now there’s one macro ready to go: JsonEncodable. As the name suggests, JsonEncodable
generates the tedious fromJson and toJson methods for you.
Macros don’t require anything extra to run, just add the appropriate annotation that you need to your code and observe as the boilerplate code is generated in real time! With them, code is not written to the disk, so say goodbye to the part keyword. Macros directly augment the existing class.
Macros, as a static metaprogramming tool, provide an alternative to runtime code generation solutions (such as build_runner, json_serializable). Macros eliminate the need for a secondary tool, being integrated into Dart language, executing automatically in the background by Dart tools with every keystroke of your keyboard
Let’s compare 3 different code snippets, first without any code gen, second with Freezed and then third with macros
Just typing this part out took a lot longer than it should for such a generic boilerplate. Obviously this is not even the whole class, it’s still missing the hashCode
, ==
operator and possibly the toString
overrides, and then do this for every (or at least most) model classes, and it turns out you’ve spent a lot of time on boilerplate code that is a lot of the time - error prone.
This looks a lot less error prone than manually writing the functions, but now you’ve got 2 new files that you need to work around, push to the project github or set up .gitignore
. A lot less work than with manual writing, but still there are some parts of these files that could be considered as boilerplate.
And that’s it! No other code needed to make this work. While you are typing the last semicolon the code is already generated and ready to be used. After writing this class we can go to some other file, and be able to do things like this:
Macros help you focus on the important stuff—the core logic of your product—and free you from the time-consuming, boring tasks that are essential but often get in the way.
Set up the environment:
import 'package:json/json.dart';
dart run --enable-experiment=macros bin/my_app.dart
Your first custom macro should have two key segments, the macro
keyword and an interface which determines for which interface the macro is determined. You can find the list of existing interfaces here.
For example, a macro that is applicable to enums, and adds new declarations to the enum, would implement the EnumDefinitionMacro interface:
With your custom macro created, you are ready to add it to a declaration, like below:
The Important thing to keep in mind is that at a high-level macros are using builders methods to combine properties of your declaration with identifiers on those properties, gathered through introspection of the codebase
The release of macros to stable is, as of the time of writing, unknown. A specific date has not yet been set due to the fact that macros work by deeply introspecting the codebase in which they’re applied. The general target for the release of JsonEncodable macro is projected to be until the end of 2024, and the stable release of the full functionality, including creating custom macros, for early-to-mid 2025.
Augmentation via the ‘augment’ keyword is the next step of evolution of the part
keyword and part files, just without the extra syntax that makes your classes less clean. Augmentation allows defining class functions outside of the main class file.
For example we have this main class Person
:
Now with the base class set, we can create our own json serialisation methods in a different part of the project, like this:
And after adding the import below, you will be good to go!
To improve the developer experience, of course! There is nothing wrong with these packages, they do the job perfectly, but with macros we make code cleaner by removing the _$
syntax needed for the packages mentioned above, as well as reduce the amount of workload on the developer to manage gitignored files or on peer review scroll endlessly over generated files to get to the crux of the pull request.