Open simolus3 opened 4 years ago
I like this idea generally - I view it as essentially a DI implementation for builders. Some eventual implementation could possibly piggyback on an existing DI package to do the heavy lifting.
That being said at this time it would probably not be a high priority for us, and even reviewing a design and implementation for this would be more work than we can commit to in the short term - especially considering the NNBD rollout which is fast approaching. We will likely be very focused on that for the next couple quarters.
In the meantime, note that you can actually do something similar to this today. Instead of providing an actual builder, you can release a library as a package which has Builder classes in it and users can either extend those classes or pass you in implementations of interfaces via the constructor. Those users then have to declare their own builder in build.yaml
etc which is a bit more verbose than what this suggests, but ultimately can accomplish most of the same things.
One example of this is JsonSerializableGenerator which takes a list of TypeHelper
s.
Request
I'd like to have some kind of plugin system for builders. On a high level, third-party packages should be able to "inject" code into a builder, so that its behavior can be tailored for specific use-cases that the build author can't or doesn't want to support.
More concise, it could allow a builder to declare abstract interfaces for it to consume. Other packages can announce that they provide an implementation for those interfaces. During a build, the builder can request a list of all implementations from the build system and call methods on them. Service discovery could happen statically, say based on
build.yaml
content while generating the build script.Motivation
I believe that builder authors can benefit from a plugin system in different ways. First, it helps reducing complexity with better modularization: Builders usually have to deal with a wide-range of requirements related to their domain, which introduces complexity. Since most builders generate Dart code directly, there's little chance of modularizing that across different packages. By implementing only the core logic and delegating further tasks to different packages via interfaces, builders become easier to write and maintain. Further, since those interfaces are public and can be implemented by everyone, users can tailor existing builders to very specific scenarios instead of writing their own builders from scratch.
Most other build systems support this kind of communication in some way. For instance, different Gradle plugins can communicate with each other. This is commonly used for compile-time code modification, e.g. with Kotlin compiler plugins.
Example use-cases
build_*_compilers
:track-widget-creation
logic from FlutterPossible api
Finding implementations of a declared interface should be easy to understand and debug. So a good candidate is static resolution while generating the build script. To make that feasible, interfaces could be declared in
build.yaml
:Another package, which doesn't have to declare a builder on its own, could then mark that it provides an implementation for that interface:
Now, if a build ran on a user package that depends on both
my_generator
andsupplement
, the builder should be able to obtain the implementation from the other package:Having the actual instance available, the builder can now use it.
I know that this is a rather large change, and it's completely understandable if this isn't a priority for the Dart team. I would love to see some kind of service discovery or plugins for builders, so I'd be glad to help implementing this. All kinds of feedback on the overall idea and the api are greatly appreciated of course.