Open felangel opened 2 years ago
Hi @felangel
The proposal looks great! This definitely fits my needs for at_app. One thought would be on handling variable inheritance:
Let's say that super_brick
has variable foo
.
In my sub_brick
, is there a way to define a value for foo
without requiring it as an input variable when generating the sub_brick
template? As in, can I define a value for foo
within the sub_brick
template, rather than requiring input for it?
Like in the classic example:
class Shape {
int sides;
Shape(this.sides);
}
class Square extends Shape {
Square() : super(4); /// Don't need to pass [sides] to create a [Square]
}
Hi @XavierChanth 👋
The proposal looks great! This definitely fits my needs for at_app.
That's great to hear 🚀
One thought would be on handling variable inheritance:
Let's say that super_brick has variable foo. In my sub_brick, is there a way to define a value for foo without requiring it as an input variable when generating the sub_brick template? As in, can I define a value for foo within the sub_brick template, rather than requiring input for it?
One way to address that would be to use reusable blocks in the base template. For example if we had main.dart
in the super_brick:
void main() {
print('Hello {{name}}');
}
We could instead rewrite it to be configurable:
void main() {
print('Hello {{$content}}{{name}}{{/content}}');
}
Then in sub_brick's main.dart
we can do:
{{<super}}
{{$content}}Felix{{/content}}
{{/super}}
Which would result in:
void main() {
print('Hello Felix');
}
Another option would be to introduce a pre_prompt
hook which executes prior to prompting for variables which would allow us to inject a default value:
// pre_prompt.dart
import 'package:mason/mason.dart';
void run(HookContext context) {
context.vars = {'name': 'Felix'};
}
Let me know what you think and thanks again for the feedback!
Looking forward to this feature.
I am most excited about the brick registry as I have had to depend on github to source control my brick templates. The ability to choose a specific template version is GOLD! One can now advance a brick without breaking other bricks depending on it
One way to address that would be to use reusable blocks in the base template.
I would prefer this feature, but I think both are a candidate depending on the use case.
Hey @felangel 👋
So excited to see this feature! Just a few quick clarifying q's I thought of:
When a brick B which requires variables {x, y}, extends brick A which requires variables {x, z}, variables {x, y, z} are required when generating brick B.
What happens when two bricks share the same variable name (in this case x), but have different types associated with it (ie brick A it's a string, and brick B it's a boolean)? Imo, that should be an error at mason make
time, but could be persuaded otherwise. On a similar note, who's prompt is chosen if a custom prompt is defined? I would expect B's prompt since it's the most specific I guess, but could totally see other sides.
I love the idea of chaining hooks like that! I may make templates just for their hooks lol. My q is, when chaining those hooks, will they share a HookContext? Mainly I'm curious if the vars from the super brick will be passed into the context in the sub bricks. I think it'd be sweet if they could!
On the note of hook execution, if you had a brick C
that extends B
and B
extends A
, would the execution be:
That's what I'd expect, so I'm just curious.
Other than those qs, everything made sense to me and felt very natural. I do think some of the features using the {{super}} prop as well as hook execution should be well documented as they seem pretty precise, but they make sense if you think it through, and it really only affects the brick makers and not people using bricks. Especially when the repository is all set up, I suspect most people will use standard bricks from there and not have to worry about those specifics 🚀
Very exciting stuff! It feels like mason is turning into a very powerful tool for automating a ton of repetitive dev tasks, which is super cool. 💯 Thanks Felix!
This looks very promising! I really like the proposal!
I wonder if besides {{<super}}
perhaps having the concept of imports
and sections
could be a more flexible approach. Similar to include
in Blade Template, or also to template
and macros
in dart doc.
Besides that, I think the "Hook Execution" feels natural.
In addition, I think in some scenarios, it would also be nice to have the option on how to perform the Conflict Resolution.
Hope the feedback helps!
I love the idea of extending bricks!
one question:
will having a subbrick allow me to import code from the parent brick? the reason I ask is that I might want to have 1 meta brick as a parent that hosts some reusable code for the subbricks. i.e:
core
meta-brick
-- page
subbrick
-- useCase
subbrick
and both page
's and useCase
's post_gen.dart
hooks would need to replace text in the same file, but in different places, thus I'd have a method in core
:
Future<void> replaceContententsInRegistry(String from, String to) {
...
}
It would be awesome to be able to reference that method from the core brick in the page
and useCase
subbricks
I love the idea of extending bricks!
one question:
will having a subbrick allow me to import code from the parent brick? the reason I ask is that I might want to have 1 meta brick as a parent that hosts some reusable code for the subbricks. i.e:
core
meta-brick --page
subbrick --useCase
subbrickand both
page
's anduseCase
'spost_gen.dart
hooks would need to replace text in the same file, but in different places, thus I'd have a method incore
:Future<void> replaceContententsInRegistry(String from, String to) { ... }
It would be awesome to be able to reference that method from the core brick in the
page
anduseCase
subbricks
You should be able to achieve this by extracting the common code into a package and installing the package as a dependency for both hooks either via git or pub.dev
Looking forward to this feature!
Proposal: Brick Template Inheritance
Description
As a developer, I want to be able to compose bricks from other bricks so that I can simplify, reuse, and reduce the maintenance cost of bricks.
For example, suppose we are maintaining a Flutter app brick called
my_flutter_app
which builds on the standardflutter create
template. Currently, we must duplicate and keep up-to-date the entire application (includingiOS
,android
,web
, etc.) which are not specific to our brick. It would be a lot simpler and easier to maintain if it were possible to create aflutter_core
brick and specify thatmy_flutter_app
extendsflutter_core
.Proposal
I propose adding the ability to have a brick
extend
anotherbrick
.The above
brick.yaml
specifies thatmy_flutter_app
builds on top of thev1.0.0
of theflutter_core
brick.As a result, when generating
my_flutter_app
,mason
will:v1.0.0
offlutter_core
flutter_core
brick codemy_flutter_app
brick on top offlutter_core
a. Any conflicting files will be overwrittenbrick.yaml extends keyword
The
extends
value must be of the format:<brick>@v<version>
when referencing a brick hosted in a registry (coming soon).version
can be one of the following:v<major_version>
- signifying the latest minor version (e.g.v1
~>>= 1.0.0 <2.0.0
>)v<major_version>.<minor_version>
- signifying the latest patch version (e.g.v1.1
~>>= 1.1.0 < 1.2.0
>)v<major_version>.<minor_version>.<patch_version>
- the exact version (e.g.v1.2.3
~>1.2.3
)<git_url>:<path>@<ref>
when referencing a brick hosted in a git repository.ref
can be one of the following:main
)d45751b
)v1
)Example Uses
Brick Inheritance Conflict Resolution
Suppose we have:
If both
sub_brick
andsuper_brick
generate a file with pathP
and contentsC
andC’
respectively, the outcome of generatingsub_brick
will be a file with pathP
and contents:C'
.For example, if
super_brick
contains:And if
sub_brick
contains:The result of generating
sub_brick
would be:Where files marked with
**
came fromsub_brick
.Replaceable Blocks
A file in
sub_brick
can reference the contents of the conflicting file in thesuper_brick
via{{<super}}
.In the above example if the contents of
main.dart
insuper_brick
are:And the contents of
main.dart
insub_brick
are:The resulting
main.dart
would look like:Variable Resolution
When a brick
B
which requires variables {x, y}, extends brickA
which requires variables {x, z}, variables {x, y, z} are required when generating brickB
. The variables can still either be passed via args:mason make B --x <X> --y <Y> --z <Z>
, via a configuration file, via commandline prompt.Hook Execution
When a brick
B
which has apre_gen
andpost_gen
hook extends brickA
which also has apre_gen
andpost_gen
hook, the result of generating brickB
is:pre_gen
Apost_gen
Apre_gen
Bpost_gen
BReferences / Inspiration