Using drift classes in other builders
It is possible to use classes generated by drift in other builders. Due to technicalities related to Dart's build system and source_gen
, this approach requires a custom build configuration. For complex builds like this, we recommend running drift in it's modular mode. This more is more efficient for larger builds and can be enabled by putting this content in a file called build.yaml
next to your pubspec.yaml
:
targets:
drift:
auto_apply_builders: false
builders:
drift_dev:modular:
enabled: true
$default:
dependencies:
# run drift's builder first
- ":drift"
builders:
# This builder is enabled by default, but we're using the modular builder in
# its own target instead.
drift_dev:
enabled: false
With modular generation, you'll have to replace the part
statement in the database file with an import to filename.drift.dart
. Also, your database class now extends from $DatabaseName
, without a leading underscore.
By generating independent libraries, drift can manage imports on its own. By declaring a dependency in build.yaml
, the build system also ensures that drift-generated files are ready before built_value
or other builders that need to see them are running.
A full example is available as part of the drift repo.
If you run into any problems with this approach, feel free to open an issue on drift.
The technicalities, explained
Almost all code generation packages use a so called "shared part file" approach provided by source_gen
. It's a common protocol that allows unrelated builders to write into the same .g.dart
file. For this to work, each builder first writes a .part
file with its name. For instance, if you used drift
and built_value
in the same project, those part files could be called .drift.part
and .built_value.part
. Later, the common source_gen
package would merge the part files into a single .g.dart
file.
This works great for most use cases, but a downside is that each builder can't see the final .g.dart
file, or use any classes or methods defined in it. To fix that, drift offers other builders - drift_dev|not_shared
and drift_dev|modular
- those will generate a separate file only containing code generated by drift. So most of the work resolves around disabling the default generator of drift and use the non-shared generator instead.
Finally, we need to the build system to run drift first, and all the other builders otherwise. This is why we split the builders up into multiple targets. The first target will only run drift, the second target has a dependency on the first one and will run all the other builders.