Extending SMF
The modules of SMF are ordinary Dart packages built on smf_contracts. A module of yours follows the same rules and goes through the same checks as the built-in ones. The pages of this section show how to write one, test it and generate apps with it.
What you can write
- A feature has screens with their routes and their state for each state manager, and gets its services through dependency injection. It can keep the user from the rest of the app with a guard, and ask for a condition, such as an account, on the routes that need one. See Write a feature module.
- An infrastructure module sets up a library or a service with start-up code, native settings, dependencies, checks of the machine and commands that run after generation. See Write an infrastructure module.
- A module of either kind can have a setting that the app remembers and shows on its settings screen, texts in the languages of the app, and notes for the coding agents that work on the app. See Add a setting and Texts.
- A provider of a role can be another router, DI container, state manager or layout, a service for analytics, crash reporting, events or preferences, sign-in, a settings screen, a theme, or the texts of the app. See Provide a role.
- A new role is a replaceable part of an app that SMF does not have yet, with its sockets, its template, its options and its rules. See Define a role.
Before you start, read the module model and module independence, since the rules that the pipeline enforces follow from them.
How a module reaches an app
smf offers a fixed list of modules. To generate apps with a module of yours, build a command of your own on smf_flutter_cli, which exports the command line as runCli and its modules as smfModules:
import 'dart:io';
import 'package:smf_counter/smf_counter.dart';
import 'package:smf_flutter_cli/smf_flutter_cli.dart';
Future<void> main(List<String> arguments) async {
final code = await runCli(
arguments,
modules: const [...smfModules, CounterModule()],
);
await Future.wait<void>([stdout.flush(), stderr.flush()]);
exit(code);
}
The command has every option and question of smf create, and it offers your module next to the built-in ones:
dart run bin/my_smf.dart create my_app -m home,counter,bottom_tabs,bloc
A module that many apps need can also become part of SMF itself; see Contributing. Publish and use a module covers both ways.
The pages of this section
- A module package covers the layout of the package, its bricks and their bundles.
- Write a feature module builds a counter screen with BLoC and Riverpod variants from start to end, declares a guard, and asks for a condition on a route.
- Write an infrastructure module covers sockets, dependencies, notes for coding agents, checks of the machine and steps after generation.
- Add a setting builds a module with a setting that the app remembers and shows on its settings screen.
- Texts covers the texts of a module in the languages of the app.
- Provide a role covers plain providers, service roles, listeners of the router and providers that render the data of their role. Pages of their own cover the guards in a router and four more roles: the settings screen, the localization, the theme and sign-in.
- Define a role covers sockets, the interface, the template, options and their modes, conditions for routes and rules.
- Templates lists the rules of the bricks.
- Test a module covers the contract harness and the checks of the package.
- Rules for modules is a checklist.
- Publish and use a module explains how a module reaches users.
The API reference of every type is on pub.dev: smf_contracts for the module model and smf_pipeline for the harness.