Welcome to Flutter Modular!
A smart project structure.
View Example
Β·
Report Bug
Β·
Request Feature
Let's find out how to implement a Modular structure in your project.
Modular proposes to solve two problems:
In a monolithic architecture, where we have our entire application as a single module, we design our software in a quick and elegant way, taking advantage of all the amazing features of Flutterπ. However, producing a larger app in a "monolithic" way can generate technical debt in both maintanance and scalability. With this in mind, developers adopted architectural strategies to better divide the code, minimizing the negative impacts on the project's maintainability and scalability..
By better dividing the scope of features, we gain:
With a more readable code, we extend the life of the project. See example of a standard MVC with 3 features(Auth, Home, Product):
.
βββ models # All models
β βββ auth_model.dart
β βββ home_model.dart
β βββ product_model.dart
βββ controller # All controllers
β βββ auth_controller.dart
β βββ home_controller.dart
β βββ product_controller.dart
βββ views # All views
β βββ auth_page.dart
β βββ home_page.dart
β βββ product_page.dart
βββ core # Tools and utilities
βββ app_widget.dart # Main Widget containing MaterialApp
βββ main.dart # runApp
Here we have a default structure using MVC. This is incredibly useful in almost every application.
Let's see how the structure looks when we divide by scope:
.
βββ features # All features or Modules
β ββ auth # Auth's MVC
β β βββ auth_model.dart
β β βββ auth_controller.dart
β β βββ auth_page.dart
β ββ home # Home's MVC
β β βββ home_model.dart
β β βββ home_controller.dart
β β βββ home_page.dart
β ββ product # Product's MVC
β βββ product_model.dart
β βββ product_controller.dart
β βββ product_page.dart
βββ core # Tools and utilities
βββ app_widget.dart # Main Widget containing MaterialApp
βββ main.dart # runApp
What we did in this structure was to continue using MVC, but this time in scope. This means that each feature has its own MVC, and this simple approach solves many scalability and maintainability issues. We call this approach "Smart Structure". But two things were still Global and clashed with the structure itself, so we created Modular to solve this impasse.
In short: Modular is a solution to modularize the route and dependency injection system, making each scope have its own routes and injections independent of any other factor in the structure. We create objects to group the Routes and Injections and call them Modules.
Modular is not only ingenious for doing something amazing like componentizing Routes and Dependency Injections, it's amazing for being able to do all this simply!
Go to the next topic and start your journey towards an intelligent structure.
Does Modular work with any state management approach?
Can I use dynamic routes or Wildcards?
Do I need to create a Module for all features?
flutter_modular was built using the engine of modular_core that's responsible for the dependency injection system and route management. The routing system emulates a tree of modules, just like Flutter does in it's widget trees. Therefore we can add one module inside another one by creating links to the parent module.
Our first goal will be the creation of a simple app with no defined structure or architecture yet, so that we can study the initial components of flutter_modular
Create a new Flutter project:
flutter create my_smart_app
Now add the flutter_modular to pubspec.yaml:
dependencies:
flutter_modular: any
If that succeeded, we are ready to move on!
π‘ TIP: Flutter's CLI has a tool that makes package installation easier in the project. Use the command:
(flutter pub add flutter_modular)
We need to add a ModularApp Widget in the root of our project. MainModule and MainWidget will be created in the next steps, but for now let's change our main.dart file:
import 'package:flutter/material.dart';
void main(){
return runApp(ModularApp(module: /*<MainModule>*/, child: /*<MainWidget>*/));
}
ModularApp forces us to add a main Module and main Widget. What are we going to do next? This Widget does the initial setup so everything can work as expected. For more details go to ModularApp doc.
π‘ TIP: It's important that ModularApp is the first widget in your app!
A module represents a set of Routes and Binds.
We'll see more info about these topics further below.
We can have several modules, but for now, let's just create a main module called AppModule:
import 'package:flutter/material.dart';
import 'package:flutter_modular/flutter_modular.dart';
void main(){
return runApp(ModularApp(module: AppModule(), child: <MainWidget>));
}
class AppModule extends Module {
@override
List<Bind> get binds => [];
@override
List<ModularRoute> get routes => [];
}
Note that the module is just a class that inherits from the Module class, overriding the binds and routes properties. With this we have a route and injection mechanism separate from the application and can be both applied in a global context (as we are doing) or in a local context, for example, creating a module that contains only binds and routes only for a specific feature!
We've added AppModule to ModularApp. Now we need an initial route, so let's create a StatelessWidget to serve as the home page.
import 'package:flutter/material.dart';
import 'package:flutter_modular/flutter_modular.dart';
void main(){
return runApp(ModularApp(module: AppModule(), child: <MainWidget>));
}
class AppModule extends Module {
@override
List<Bind> get binds => [];
@override
List<ModularRoute> get routes => [
ChildRoute('/', child: (context, args) => HomePage()),
];
}
class HomePage extends StatelessWidget {
Widget build(BuildContext context){
return Scaffold(
appBar: AppBar(title: Text('Home Page')),
body: Center(
child: Text('This is initial page'),
),
);
}
}
We've created a Widget called HomePage and added its instances in a route called ChildRoute.
π‘ TIP: There are two ModularRoute types: ChildRoute and ModuleRoute.
- ChildRoute: Serves to build a Widget.
- ModuleRoute: Concatenates another module.
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the appropriate tag. Don't forget to give the project a star! Thanks again!
git checkout -b feature/AmazingFeature
)git commit -m 'Add some AmazingFeature'
)git push origin feature/AmazingFeature
)Remember to include a tag, and to follow Conventional Commits and Semantic Versioning when uploading your commit and/or creating the issue.
Flutterando Community
This fork version is maintained by Flutterando.