Closed craiglabenz closed 2 years ago
My plan had been to wait until the static meta programming feature in Dart was available to add typesafe routing but I like the idea to add it optionally now. Do you have a PR to share?
No PR to share yet. I think this would be a significant amount of work, so I'd want to brainstorm it together and get full buy-in before breaking any ground.
Having a generated file that provided for type safe wrappers for named routes would make an excellent addition to go_router.
@craiglabenz and I did some brainstorming and came up w/ the following core abstraction to noddle on:
// go_router provides
abstract class MaterialGoRoute {
Widget builder(BuilderContext context, GoRouterState state) =>
MaterialPage(key: state.pageKey, child: buildPage(context, state));
Widget buildPage(BuildContext context, GoRouterState state);
}
// user defines a top-level route
@goroute('home', path: '/')
class HomeRoute extends MaterialGoRoute {
@override
Widget buildPage(BuildContext context, GoRouterState state) => HomePage();
}
// user defines a sub-route (under HomeRoute)
@goroute('family', path: 'family/:fid', parent: HomeRoute)
class FamilyRoute extends MaterialGoRoute {
@goparam('fid') final String fid;
FamilyRoute(this.fid);
@override
Widget buildPage(BuildContext context, GoRouterState state) {
final family = Families.family(fid);
return FamilyPage(family);
}
}
// user defines a sub-route (under FamilyRoute)
@goroute('person', path: 'person/:pid', parent: Family)
class PersonRoute extends MaterialGoRoute {
@goparam('fid') final String fid;
@goparam('pid') final String pid;
PersonRoute(this.fid, this.pid);
@override
Widget buildPage(BuildContext context, GoRouterState state) {
final family = Families.family(fid);
final person = family.person(pid);
return PersonPage(family, person);
}
}
//... codegen magic happens...
// user can call static push/go methods; compiler enforces the right params
HomeRoute.go(context);
FamilyRoute.go(context, fid: family.id);
PersonRoute.go(context, fid: family.id, pid: person.id);
PersonRoute.push(context, fid: family.id, pid: person.id);
cc @kevmoo
Something like this?
?
Here is my opinion on typed routing and its corresponding documentation.
Do bear in mind that I have strong opinions regarding code gen and routing so feel free to ignore my remark and please do not feel offended if I express a different opinion than yours.
I love what this is trying to solve.
About the docs, the issue is well explained but the example is quite untruthful imo:
final selectedAuthor = libraryInstance.allAuthors.firstWhereOrNull((a) => a.id == authorId);
Would still be needed even with code gen. I would remove that part and write AuthorDetailsScreen(authorId: authorId)
.
I like the fact that all @TypedGoRoute
don’t have to be at the same place if they can be defined in different files.
In my opinion:
@TypedGoRoute
have to be in the same file, I would have one file with the GoRouteData
, and another with the @TypedGoRoute
. In this case I am not certain that being able to create multiple @TypedGoRoute
is useful.In any case, this should be mentioned in the docs.
Also in the doc I find the order of the route in the example quite confusing at first. Since this is so early in the doc my first read took some effort to see which things wereGoRouteData
and which was TypeGoRoute
.
Is there a reason why we cannot have errorPageBuilder: $appErrorPageBuilder
? This would match the routes: $appRoutes
construction used for the routes.
I like the compiler error, this is what this entire thing is built for so that’s great :+1:
I’m not sure about the .go
method. On the one hand I find it fancy (in a good way), on the other hand I don’t like the concept:
I guess it doesn’t matter here but it still bugs me in a way.
The solution would be to be able to use context.goTyped(MyGoRouteData())
. This could be an extension generated by code gen so that if you don't use code gen you don't see it?
Optional parameter = Query Parameters | Required parameters = Path Parameters is very opinionated. I think this is a great default behavior however what if you have an optional parameter with a default value ? Or a required parameter which can be null ?
About $extra
I am quite confused by this but maybe it’s my ignorance about code gen: could we not directly use this.person
, instead of forcing it to be $extra
(with the ever so confusing $
)?
The rule (if not using $extra
) would be that if a parameter is of a type which is not supported by GoRouter, it won’t be part of the path.
Also are named extra parameters allowed ({required this.$extra}
)? I love named parameters ^^
About the concept of extra parameters
I won’t hide the fact that I don’t like extra parameters (VRouter bears witness), but this might be a chance to solve the issues it has. Mainly the fact that when navigating with the url to a GoRouteData
with an extra parameter what will happen? This is an error that can stay silent for a long time (since devs do not always check that typing a url works), being a really bad runtime error!
A solution could be to require them to have a default value, and check that they do during code gen (I don’t know if this is possible).
No comment on the API, however the example is wrong I think:
// This is what is used
final loggingIn = state.subloc == HomeRoute().location
// But this should be used instead right?
final loggingIn = state.subloc == LoginRoute().location
Wait, do you mean that overriding build
is never compulsory ? I don’t really like this because this does not play well with IDE. Instead I would have something like GoRedirectRouteData
.
However this is in line with the current API so I understand the choice. I just don’t like it, neither here nor in the original GoRoute
. As discussed with @csells I think having GoRoute.redirect
which the IDE autocomplete with redirect
and GoRoute
which autocompletes with path
and pageBuilder
would be much better. (This could even allow the use of @Depreciated which would not make it a breaking change). Anyhow this is not the subject here but if this was the direction the API was taking, I would introduce a GoRedirectRouteData
for redirects.
To change the page key, could we have a final Key? pageKey
attribute that would be used in the page by default? This would make changing the key while keeping the default page much easier.
Note on the docs if this pageKey
is possible: I would only keep the text of this section and merge it with “Custom transition”
I would give the child inbuildPage
directly. Keep GoRouterState
but give the child directly for make things easier:
Page<void> buildPage(BuildContext context, Widget child, GoRouterState state) => FancyPage(
key: state.pageKey,
child: child,
);
That’s not vital but it took me some time to realize why build(context, state)
was used and kept me from focusing on what mattered (i.e. the creation of a custom Page
). This would solve this issue.
I really don’t like the naming conventions. According to me in Flutter there is Screen
> Route
> Page
> Page Stack
(> indicate a composition dependency). The examples are already using the name Page
for Screen
. In this API we use Route
for Page Stack
. You can see how much confusing this is ^^
I like what it is trying to solve.
I don’t like code generation, but I guess that’s better than runtime errors. If macro could solve this too once they land, that would be awesome (but I understand that you don’t want to wait for the dart language to change).
On that note, if the long term goal is to move to macros: Are macro mature enough that we could know if this could easily be a 1 to 1 replacement? I think the code gen API should strive to be replaceable by macro without feature change once they arrive.
What happens if a GoRouteData
subclass is created but not part of the Route tree
? The error will only show when SubClassGoRouteData.go(context)
is called?
Conversely, what happens if a GoRouteData
is put in the Route tree
but does not have the right parameters?
Also the signature of GoRouteData.build
method changes from Widget build(BuildContext context)
to Widget build(BuildContext context, GoRouterState state)
every few examples :smile:
@lulupointu thanks for the great feedback. I left some responses inline.
About the docs, the issue is well explained but the example is quite untruthful imo:
final selectedAuthor = libraryInstance.allAuthors.firstWhereOrNull((a) => a.id == authorId);
Would still be needed even with code gen. I would remove that part and write
AuthorDetailsScreen(authorId: authorId)
.
That's true. The part I meant to highlight is the line of code above it, which is not code you have to write when using codegen:
final authorId = int.parse(state.params['authorId']!);
- If all
@TypedGoRoute
have to be in the same file, I would have one file with theGoRouteData
, and another with the@TypedGoRoute
. In this case I am not certain that being able to create multiple@TypedGoRoute
is useful.- If they can be in separate files, then that’s awesome
You need to annotate the top-level route, so the route tree needs to be in the same place as that.
Also in the doc I find the order of the route in the example quite confusing at first. Since this is so early in the doc my first read took some effort to see which things were
GoRouteData
and which wasTypeGoRoute
.
Yep. Naming is hard. I'm open to suggestions.
Error page builder
Is there a reason why we cannot have
errorPageBuilder: $appErrorPageBuilder
? This would match theroutes: $appRoutes
construction used for the routes.
What would it do? How would the codegen know what code to produce?
The solution would be to be able to use
context.goTyped(MyGoRouteData())
. This could be an extension generated by code gen so that if you don't use code gen you don't see it?
In a world where Dart allowed for overriding the go() method with different route types, that would certainly be an option.
Query and path parameters
Optional parameter = Query Parameters | Required parameters = Path Parameters is very opinionated. I think this is a great default behavior however what if you have an optional parameter with a default value ? Or a required parameter which can be null ?
This is already have go_router works. I don't want the typed routing to change the foundations of go_router; merely provide a boost in robustness and productivity.
I am quite confused by this but maybe it’s my ignorance about code gen: could we not directly use
this.person
, instead of forcing it to be$extra
(with the ever so confusing$
)? The rule (if not using$extra
) would be that if a parameter is of a type which is not supported by GoRouter, it won’t be part of the path.
I want to be quite clear that $extra does not go through the location, making it worthless for deep and dynamic linking and, if you're going to use it, it's OK for it to be a little weird so that you'll have to think twice about using it.
The good news is that if you do use $extra and then change your mind, you can change your route classes and let the compiler guide you to all of the users of those routes for you to change.
Also are named extra parameters allowed (
{required this.$extra}
)? I love named parameters ^^
Yes.
I won’t hide the fact that I don’t like extra parameters (VRouter bears witness), but this might be a chance to solve the issues it has. Mainly the fact that when navigating with the url to a
GoRouteData
with an extra parameter what will happen? This is an error that can stay silent for a long time (since devs do not always check that typing a url works), being a really bad runtime error!
I don't like them either but it unblocks some scenarios for folks that want to use go_router but don't care about deep and dynamic linking. I want to enable it but I don't want to make it without speed bumps.
// This is what is used final loggingIn = state.subloc == HomeRoute().location // But this should be used instead right? final loggingIn = state.subloc == LoginRoute().location
Good catch!
Route-level redirection
Wait, do you mean that overriding
build
is never compulsory ? I don’t really like this because this does not play well with IDE. Instead I would have something likeGoRedirectRouteData
.
I hear you on using more types == letting the compiler be stricter. However, it also requires the user to go to the effort of switching types. By the time they do that, I feel like they could've implemented the redirect method.
Transition override
To change the page key, could we have a
final Key? pageKey
attribute that would be used in the page by default? This would make changing the key while keeping the default page much easier.
In my experience, switching keys is rare; If I can keep the number of concepts down, then that's a win overall. If it becomes a problem, it's easy enough to add over time.
Custom
I would give the child in
buildPage
directly. KeepGoRouterState
but give the child directly for make things easier:Page<void> buildPage(BuildContext context, Widget child, GoRouterState state) => FancyPage( key: state.pageKey, child: child, );
The idea is that you override buildPage or build -- there's no real reason to override both or to have the result of one passed to the other.
That’s not vital but it took me some time to realize why
build(context, state)
was used and kept me from focusing on what mattered (i.e. the creation of a customPage
). This would solve this issue.
That was an earlier draft of the spec. The example code has been updated.
Naming conventions
I really don’t like the naming conventions. According to me in Flutter there is
Screen
>Route
>Page
>Page Stack
(> indicate a composition dependency). The examples are already using the namePage
forScreen
. In this API we useRoute
forPage Stack
. You can see how much confusing this is ^^
I agree that screen vs. route vs. page vs page stack is poorly understood in Flutter. I made a stab at naming in the existing go_router package and I don't thing changing the terminology for typed usage would be helpful for folks.
On that note, if the long term goal is to move to macros: Are macro mature enough that we could know if this could easily be a 1 to 1 replacement? I think the code gen API should strive to be replaceable by macro without feature change once they arrive.
That's the ideal for sure.
What happens if a
GoRouteData
subclass is created but not part of theRoute tree
? The error will only show whenSubClassGoRouteData.go(context)
is called? Conversely, what happens if aGoRouteData
is put in theRoute tree
but does not have the right parameters?
go() will be missing from any GoRouteData-derived class that isn't part of the @TypedGoRoute() attribute, so it will be a compile-time error.
Also the signature of
GoRouteData.build
method changes fromWidget build(BuildContext context)
toWidget build(BuildContext context, GoRouterState state)
every few examples 😄
Can you point those out to me? I looked again through the docs and couldn't find any instances of Widget build(BuildContext context, GoRouterState state)
. The signature can only be Widget build(BuildContext context)
.
I will answer only what makes sense, but thanks for all the other answers as well.
That's true. The part I meant to highlight is the line of code above it, which is not code you have to write when using codegen
I know, what I am saying is that is would make more sense to change the example to:
GoRoute(
path: ':authorId',
pageBuilder: (context, state) {
// require the authorId to be present and be an integer
final authorId = int.parse(state.params['authorId']!);
return MaterialPage<void>(
key: state.pageKey,
child: AuthorDetailsScreen(authorId: authorId),
);
},
),
Since this focuses on the part the codegen is trying to solve.
Also in the doc I find the order of the route in the example quite confusing at first. Since this is so early in the doc my first read took some effort to see which things wereGoRouteData and which was TypeGoRoute.
Yep. Naming is hard. I'm open to suggestions.
I was not talking about the naming here but rather the organization in the file. Here is what would make more sense to me:
// Define your [GoRouteData]s
class HomeRoute extends GoRouteData {...}
class FamilyRoute extends GoRouteData {...}
class PersonRoute extends GoRouteData {...}
class LoginRoute extends GoRouteData {...}
// Bind them to the path using [TypedGoRoute]
@TypedGoRoute<LoginRoute>(path: '/login');
@TypedGoRoute<HomeRoute>(
path: '/',
routes: [
TypedGoRoute<FamilyRoute>(
path: 'family/:fid',
routes: [
TypedGoRoute<PersonRoute>(
path: 'person/:pid',
),
],
),
],
);
But that's just me. Maybe ask other what they think (some who have never read it before if possible)
All the part about query, path and extra params
I understand you approach and it makes sense. The only thing I am still unsure: If you use $extra
and deeplink to that route, this will be a runtime error. Is that right ?
Route-level redirection Wait, do you mean that overriding build is never compulsory ? I don’t really like this because this does not play well with IDE. Instead I would have something like GoRedirectRouteData.
I hear you on using more types == letting the compiler be stricter. However, it also requires the user to go to the effort of switching types. By the time they do that, I feel like they could've implemented the redirect method.
Agree to disagree :wink:
Would you consider GoRoute.redirect
though ? :smile:
Naming I really don’t like the naming conventions. According to me in Flutter there is Screen > Route > Page > Page Stack (> indicate a composition dependency). The examples are already using the name Page for Screen. In this API we use Route for Page Stack. You can see how much confusing this is ^^
I agree that screen vs. route vs. page vs page stack is poorly understood in Flutter. I made a stab at naming in the existing go_router package and I don't thing changing the terminology for typed usage would be helpful for folks.
Actually I was not arguing about GoRoute
, my comments was for the use of ...Page
in your example (which I stand by) and about the new name GoRouteData
. Anyway you did not answer my question but I just understood why you use GoRouteData
, all good (even if still unfortunate for the Route
part)
Also the signature of GoRouteData.build method changes from Widget build(BuildContext context) to Widget build(BuildContext context, GoRouterState state) every few examples smile
Can you point those out to me? I looked again through the docs and couldn't find any instances of Widget build(BuildContext context, GoRouterState state). The signature can only be Widget build(BuildContext context).
I must have been confused with a buildPage
then. I did check now and there is indeed no issue so in any case it's all good.
Also you did not comment on the "Complete transition example" and you did not update the doc in the regard. Is there a reason ? Or maybe you missing my comment because it was hidden in a summary ?
I know, what I am saying is that is would make more sense to change the example to:
GoRoute( path: ':authorId', pageBuilder: (context, state) { // require the authorId to be present and be an integer final authorId = int.parse(state.params['authorId']!); return MaterialPage<void>( key: state.pageKey, child: AuthorDetailsScreen(authorId: authorId), ); }, ),
Since this focuses on the part the codegen is trying to solve.
Ah. Yes. I see. I just dropped in some code I copy/pasted from a sample, but you're right. Your code focuses on the issue better. I'll update the proposal.
I was not talking about the naming here but rather the organization in the file. Here is what would make more sense to me:
// Define your [GoRouteData]s class HomeRoute extends GoRouteData {...} class FamilyRoute extends GoRouteData {...} class PersonRoute extends GoRouteData {...} class LoginRoute extends GoRouteData {...} // Bind them to the path using [TypedGoRoute] @TypedGoRoute<LoginRoute>(path: '/login'); @TypedGoRoute<HomeRoute>( path: '/', routes: [ TypedGoRoute<FamilyRoute>( path: 'family/:fid', routes: [ TypedGoRoute<PersonRoute>( path: 'person/:pid', ), ], ), ], );
But that's just me. Maybe ask other what they think (some who have never read it before if possible)
Unfortunately I believe that the limitation of codegen annotations is that they have to annotate something.
All the part about query, path and extra params
I understand you approach and it makes sense. The only thing I am still unsure: If you use
$extra
and deeplink to that route, this will be a runtime error. Is that right ?
Yes. That's the reason to avoid the $extra parameter.
Would you consider
GoRoute.redirect
though ? 😄
I considered that, but it seemed redundant. Without it, I write:
GoRouter(redirect: (_) => BooksRoute().location)
with it, I write:
GoRouter.redirect(redirect: (_) => BooksRoute().location)
It doesn't seem to be a win.
Actually I was not arguing about
GoRoute
, my comments was for the use of...Page
in your example (which I stand by) and about the new nameGoRouteData
. Anyway you did not answer my question but I just understood why you useGoRouteData
, all good (even if still unfortunate for theRoute
part)
Were you suggesting a different name? Perhaps GoPage? GoPageData?
Also you did not comment on the "Complete transition example" and you did not update the doc in the regard. Is there a reason ? Or maybe you missing my comment because it was hidden in a summary ?
I missed your feedback there. Can you repeat it?
Unfortunately I believe that the limitation of codegen annotations is that they have to annotate something.
Are you sure you have read the code correctly ? I just changed the ordering of the declaration but not the code itself. What I wrote is not valid ?
Yes. That's the reason to avoid the $extra parameter.
I see. They maybe consider changing the documentation
FROM
The $extra parameter is still passed outside of the location, still defeats dynamic and deep linking and is still not recommended in general.
TO
The $extra parameter is still passed outside of the location, which means that dynamic or deep linking to its associated path not be possible. Please avoid to use it in general.
Or something along those line. The most important part being the impossibility to dynamic/deep linking. The word defeats is to vague and does not convey any meaning in itself
I considered that, but it seemed redundant. Without it, I write:
GoRouter(redirect: (_) => BooksRoute().location)
with it, I write:
GoRouter.redirect(redirect: (_) => BooksRoute().location)
It doesn't seem to be a win.
What about:
GoRouter.redirect((_) => BooksRoute().location)
Exactly the same but you harvest the power of the IDE
Were you suggesting a different name? Perhaps
GoPage
?GoPageData
?
I was thinking about a different name but a think GoRouteData
is as good as you can get.
The conceptual issue of GoRouteData
is that it's both a Page
defining thing and a Page Stack
one (just like GoRoute
), which is why GoRoute
is ok I guess, it just have nothing to do with pages but is an hybrid thing that Flutter as no object for.
Why do I say Page Stack
? Well if you navigate to PersonRoute
you will go to the stack of page [HomePage
, FamillyPage
, PersonPage
] (which are MaterialPage
s but I renamed them to make my point, you get the idea).
This is why is confusing about those API as well, but there is not much to be done about it, as I said: GoRoute
is as good of a name as any.
If I had any comment it would be about the examples, trying to as list make the naming consistent, this means changing:
HomeRoute
to HomeGoRouteData
FamillyRoute
to FamillyGoRouteData
Then people do what they want in their code but I think in the documentation this would help new comers keep track of what is what.
I missed your feedback there. Can you repeat it?
Sure:
Nits: you kept MaterialPage
as the return type of buildPage
. Use Page
instead.
I would replace the example with a fully fledged one. Currently devs:
Add to that the fact that devs are often confused by the Page API so they have a hard time differentiating what is package specific vs what is vanilla Flutter and that gives you a very poor experience.
Anyway here is how that could look like:
class FancyRoute extends GoRouteData {
@override
Widget build(BuildContext context, GoRouterState state) => FancyScreen();
@override
Page<void> buildPage(BuildContext context, Widget child, GoRouterState state) => FancyPage(
key: state.pageKey,
child: child,
);
}
class FancyPage extends Page {
FancyPage({required this.key, required this.child});
final LocalKey key;
final Widget child;
@override
Route createRoute(BuildContext context) {
return PageRouteBuilder<dynamic>(
pageBuilder: (_, animation, __) => FadeTransition(
opacity: animation,
child: child,
),
);
}
}
Oh man, please don't go crazy with codegens! The main reason I switched to GoRouter was the lack of them. 😂
I get the value of the above, but if you do decide to add this, please make it optional. And please don't bake codegen into the "main workflow" of the package.
Unfortunately I believe that the limitation of codegen annotations is that they have to annotate something.
Are you sure you have read the code correctly ? I just changed the ordering of the declaration but not the code itself. What I wrote is not valid ?
Before the @TypedGoRoute was annotating the top-level route. With your proposed reorganization, if I'm reading it correctly, that's no longer the case and the annotations don't actually annotate anything.
The most important part being the impossibility to dynamic/deep linking. The word defeats is to vague and does not convey any meaning in itself
I'll take that into account when/if this proposal ever turns into real docs for a real implementation.
What about:
GoRouter.redirect((_) => BooksRoute().location)
Exactly the same but you harvest the power of the IDE
I like syntax completion and letting the compiler tell me I did something wrong, but I'm sure this particular juice is worth the squeeze. For example, sometimes I want a conditional redirect and a pageBuilder. In that case, I have to eschew the GoRoute.redirect() ctor and choose the main GoRoute() ctor. That feels confusing to me.
If I had any comment it would be about the examples, trying to as list make the naming consistent, this means changing:
HomeRoute
toHomeGoRouteData
FamillyRoute
toFamillyGoRouteData
- etc.
Then people do what they want in their code but I think in the documentation this would help new comers keep track of what is what.
That's too much typing, I think. I really like how HomeRoute().go(context)
reads. I don't have the same fondness for HomeGoRouteData.go(context)
.
Nits: you kept
MaterialPage
as the return type ofbuildPage
. UsePage
instead.
I was relying on Dart covariance (contravariance?) and the fact that markdown is a very forgiving compilation environment. Once I have working samples and can turn this proposal into actual docs, I'll fix things like that.
I would replace the example with a fully fledged one.
class FancyRoute extends GoRouteData { @override Widget build(BuildContext context, GoRouterState state) => FancyScreen(); @override Page<void> buildPage(BuildContext context, Widget child, GoRouterState state) => FancyPage( key: state.pageKey, child: child, ); } class FancyPage extends Page { FancyPage({required this.key, required this.child}); final LocalKey key; final Widget child; @override Route createRoute(BuildContext context) { return PageRouteBuilder<dynamic>( pageBuilder: (_, animation, __) => FadeTransition( opacity: animation, child: child, ), ); } }
I don't need to do all of that in my existing untyped routing example for custom transitions. Am I missing something in that sample?
Oh man, please don't go crazy with codegens! The main reason I switched to GoRouter was the lack of them. 😂
Oh believe me. I get it. The codegen routing solutions I've seen are not worth the complexity of the build_runner, which is why I didn't start there with go_router and why I don't plan on making it the default usage. I'm hoping to leverage Dart macros when those are available, which should help make the codegen solution a lot easier, but we're not there yet.
I get the value of the above, but if you do decide to add this, please make it optional. And please don't bake codegen into the "main workflow" of the package.
That's the plan for sure.
Before the @TypedGoRoute was annotating the top-level route. With your proposed reorganization, if I'm reading it correctly, that's no longer the case and the annotations don't actually annotate anything.
Do you mean that, because there is also some codegen for GoRouteData
, even the GoRouteData
s would need to be in the same page and by defined after a @TypedGoRoute
annotation, without line return ?
I don't need to do all of that in my existing untyped routing example for custom transitions. Am I missing something in that sample?
Yeah I don't know why your sample is so complex. Isn't PageRouteBuilder
enough ? At least that's what I use in VRouter
for custom transition under the hood and nobody ever came to me with an issue on this part.
Before the @TypedGoRoute was annotating the top-level route. With your proposed reorganization, if I'm reading it correctly, that's no longer the case and the annotations don't actually annotate anything.
Do you mean that, because there is also some codegen for
GoRouteData
, even theGoRouteData
s would need to be in the same page and by defined after a@TypedGoRoute
annotation, without line return ?
I'm not talking about formatting. I'm talking about my understanding of Dart annotations which I believe require something to annotate, e.g.
// this is OK
@foo
class Something {}
// this is not
class Something {}
@foo
@kevmoo is the authority here.
I don't need to do all of that in my existing untyped routing example for custom transitions. Am I missing something in that sample?
Yeah I don't know why your sample is so complex. Isn't
PageRouteBuilder
enough ? At least that's what I use inVRouter
for custom transition under the hood and nobody ever came to me with an issue on this part.
Interesting. I think go_router's support for custom transitions is pretty simple.
I'm not talking about formatting. I'm talking about my understanding of Dart annotations which I believe require something to annotate, e.g.
I see, then it's quite counter intuitive, I though I understood the use @TypedGoRoute
but I wouldn't have thought that moving the GoRouteData
away would break the codegen. I mean it makes sense now that you say it but being clueless about codegen I thought @TypedGoRoute
was only needed at the top of a route tree
I suppose the alternative it to add a @GoRouteData
annotation which you don't like right ? Ok wouldn't that even work ?
Interesting. I think go_router's support for custom transitions is pretty simple.
Actually I did some intense tests today and your approach is more bulletproof. For reasons explained here.
Interesting. I think go_router's support for custom transitions is pretty simple.
Actually I did some intense tests today and your approach is more bulletproof. For reasons explained here.
Hey. I got lucky. : )
Reverted in 696f7d7
@csells I have a question about the approach of type safe routing. Will the way of defining GoRouter change? or the same way when meta programming is released?
@YazeedAlKhalaf – no change is planned for folks doing hand-written routing. There are some new APIs added that are used by generated code so there is less boilerplate for you to write!
This is an exploratory feature request to add a
build_runner
layer for generating type-safe wrappers aroundgoNamed
andpushNamed
.I'm imagining something like this:
Which would create something like this:
Thoughts?