routes_generator 0.0.5 routes_generator: ^0.0.5 copied to clipboard
Automatically generate routes of pages for `MaterialApp` of `flutter`. Supports group routes, parameterized pages, dynamic routes.
routes_generator #
Provides source_gen Generator
to generator routes
for MaterialApp
of flutter
.
Non-intrusive, convention over configuration, only need to install and build.
Convention #
- The
routes.dart
file used to export routes and related functions toMaterialApp
, androutes.map.dart
must be imported in the fileroutes.dart
. - The
pages
directory relative toroutes.dart
contains your app views and routes, each file contains only one routing page, generator reads all.dart
files inside this directory and generate routes map intoroutes.map.dart
. - The above two conventions apply to any directory of the project.
Usage #
Basic Routes #
Add dev_dependencies
.
dev_dependencies:
routes_generator: any
Import routes.map.dart
in the routes.dart
file (add new if it does not exist),
you do not need to add a new routes.map.dart
file, it will be automatically generated.
// routes.dart
import 'package:flutter/widgets.dart';
import 'routes.map.dart' as p;
Map<String, WidgetBuilder> routes = p.routes;
Run code generation.
$ flutter pub run build_runner build
If there are multiple routes.map.dart
, they need to be merged and used.
import 'routes.map.dart' as p;
import 'dev/routes.map.dart' as d;
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
routes: <String, WidgetBuilder>{...p.routes, ...d.routes}
);
}
}
Group Routes #
In addition to putting all routes in one Map, sometimes it is necessary to put some routes into a separate Map for special processing, such as detecting login before routing.
You need to add a private class named _RoutesGroup
and
define the supported group annotation instances, such as
class _RoutesGroup {
final String name;
const _RoutesGroup(this.name);
}
const authRequired = _RoutesGroup('authRoutes');
Add corresponding annotations on the routing page where required
@authRequired
class MySetting extends StatelessWidget {
Widget build(BuildContext context) {
// ...
}
}
Conventional annotations are private class instances.The reason for not providing annotation classes is that routing needs to be used and managed, and random group names are not allowed when grouping is specified on the page.
Parameterized #
If the page widget is parameterized, the generator will automatically inject parameters.
class ParameterizedPage extends StatelessWidget {
final String arg1;
final String arg2;
ParameterizedPage(this.arg1, {this.arg2});
}
The generated routes looks like this
Map<String, WidgetBuilder> routes = {
'/parameterized': (context) {
final Map args = ModalRoute.of(context).settings?.arguments ?? {};
return ParameterizedPage(args['arg1'], arg2: args['arg2']);
},
};
Dynamic Routes #
If the path of the page contains a directory or file name starting with an underscore (_
),
then the directory or file name will be used as a variable.
such as /dynamic/_name/_id.dart
, there are two variable in the path, name
and id
.
class DynamicPage extends StatelessWidget {
final String name;
final String id;
DynamicPage(this.name, {this.id});
}
The generated routing table is an list, which variable name ends with Dynamic
List<WidgetBuilder Function(String)> routesDynamic = [
(path) {
final reg = RegExp(r'^/dynamic/(?<name>[^\/]+)$/(?<id>[^\/]+)$');
final match = reg.firstMatch(path);
if (match == null) return null;
return (context) => DynamicPage(match.namedGroup('name'), id: match.namedGroup('id'));
},
];
That should be used in onGenerateRoute
onGenerateRoute: (RouteSettings settings) {
WidgetBuilder builder = routes[settings.name];
if (builder == null) {
for (final matcher in routesDynamic) {
builder = matcher(settings.name);
if (builder != null) {
break;
}
}
}
if (builder == null) return null;
return MaterialPageRoute(settings: settings, builder: builder);
}
Configuration #
If your project structure does not conform to the convention, or want to split the route according to the environment, such as, the development app provides more pages and features, which is very useful when switching between multiple development environments. Configuration is also provided.
Basic #
The following structure is typical and conforms to the convention.
├── lib
│ ├── dev
│ │ ├── drawer.dart
│ │ ├── pages
│ │ │ └── hosts.dart
│ │ ├── routes.dart
│ │ └── routes.map.dart
│ ├── main.dart
│ ├── main_dev.dart
│ ├── pages
│ │ ├── home.dart
│ │ ├── user
│ │ │ └── settings.dart
│ │ └── setting.dart
│ ├── routes.dart
│ ├── routes.map.dart
│ └── screen
│ ├── app.dart
│ └── home.dart
Configure it in build.yaml
. The following configuration is in accordance with the convention.
Already meet basic directory split requirements.
targets:
$default:
builders:
routes_generator:
options:
ext: ".map.dart" # generated file extension
routes:
routes.dart: # routes.dart
name: "routes" # generated variable name
pages: "pages" # pages directory, relative to `routes.dart`
Change or add the configuration to fit you situation. For example,
the route directory is views
instead of pages
.
targets:
$default:
builders:
routes_generator:
options:
ext: ".my.dart" # change generated file extension
prefix: "/app" # add default prefix `/app` to route url
routes:
my_routes.dart: # change routes file
name: "myRoutes" # change the variable name
pages: "../views" # change pages location
dev/my_routes.dart:
prefix: "/dev" # add prefix to dev route url, override default prefix `/app`
name: "devRoutes"
pages: "views"
Group #
If you have defined routing grouping in the project,
you can also modify the default grouping parameters group
.
The group
need to specify the class name and grouped field name.
targets:
$default:
builders:
routes_generator:
options:
group: "MyPageRoutes.group" # change with class name and it's field name
The annotation is defined as follows.
class MyPageRoutes {
final String group;
const MyPageRoutes(this.group);
}
@MyPageRoutes(group: 'authRoutes')
class FirstPage extends StatelessWidget {
}
This option can also be in any routes
sub-node,
which will override the default option.
targets:
$default:
builders:
routes_generator:
options:
group: "MyPageRoutes.group"
routes:
routes.dart:
group: "SubPageRoutes.group"
Ignores #
If there are non-routing page files or directories in the pages
directory,
they can be ignored by configuration
targets:
$default:
builders:
routes_generator:
options:
ignores: "**/widgets/**" # ignore all `widgets` directory in `pages`
Or configure multiple
targets:
$default:
builders:
routes_generator:
options:
ignores:
- "**/widgets/**" # ignore all `widgets` directory in `pages`
- "**.g.dart" # ignore all generated files
This option can also be in any routes
sub-node,
which will override the default option.
You can also set false
to disable this option.
targets:
$default:
builders:
routes_generator:
options:
ignores: "**.g.dart"
routes:
routes.dart:
ignores: "**/widgets/**"
dev/routes.dart:
ignores: false # disable ignore any files
Dynamic #
The suffix name of dynamic routing variable can be configured.
You can also set false
to prohibit the generation of dynamic routing.
targets:
$default:
builders:
routes_generator:
options:
dynamic: 'Dynamic'
routes:
routes.dart:
dynamic: 'Dynamic'
dev/routes.dart:
dynamic: false # disable dynamic routes