Modugo
Modugo é um sistema modular para Flutter inspirado em Flutter Modular e Go Router Modular. Ele organiza sua aplicação em módulos, rotas e injeção de dependências de forma clara e escalável. Diferente de outros frameworks, o Modugo não gerencia descarte automático de módulos.
📚 Documentação completa: bed72.github.io/Modugo
📖 Sumário
- Visão Geral
- Instalação
- Primeiros Passos
- Módulos
- Rotas
- API Declarativa (DSL)
- Guards
- Injeção de Dependência
- Sistema de Eventos
- Utilitários
- Documentação
- Contribuições
- Licença
🚀 Visão Geral
- Usa GoRouter para navegação.
- Usa GetIt para injeção de dependências.
- Dependências são registradas uma única vez ao iniciar.
- Não há descarte automático — as dependências vivem até o app encerrar.
- 5 tipos de rotas:
ChildRoute,ModuleRoute,ShellModuleRoute,StatefulShellModuleRoute,AliasRoute. - Guards com propagação automática para submódulos.
- Sistema de eventos nativo para comunicação desacoplada.
- 7 transições de página prontas para uso.
- Extensions de contexto para navegação, matching e injeção.
📦 Instalação
dependencies:
modugo: ^4.2.6
▶️ Primeiros Passos
1. Crie o módulo raiz
final class AppModule extends Module {
@override
void binds() {
i.registerSingleton<AuthService>(AuthService());
}
@override
List<IRoute> routes() => [
route('/', child: (_, _) => const HomePage()),
module('/profile', ProfileModule()),
];
}
2. Configure no main.dart
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Modugo.configure(module: AppModule(), initialRoute: '/');
runApp(const AppWidget());
}
3. Use o router
class AppWidget extends StatelessWidget {
const AppWidget({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp.router(routerConfig: modugoRouter);
}
}
📚 Guia completo: Primeiros Passos
🏗 Módulos
Cada módulo encapsula suas rotas, dependências e imports:
final class HomeModule extends Module {
@override
List<IBinder> imports() => [SharedModule()];
@override
void binds() {
i.registerLazySingleton<HomeController>(
() => HomeController(i.get<ApiClient>()),
);
}
@override
List<IRoute> routes() => [
route('/', child: (_, _) => const HomePage()),
];
}
imports()— módulos dos quais este depende (registrados antes).binds()— registra dependências no GetIt.routes()— declara as rotas do módulo.- Registro idempotente: cada módulo é registrado apenas uma vez.
📚 Detalhes: Módulos
🧭 Rotas
Tipos disponíveis
| Tipo | Uso |
|---|---|
ChildRoute |
Telas simples |
ModuleRoute |
Submódulos |
AliasRoute |
Caminhos alternativos para a mesma tela |
ShellModuleRoute |
Layout compartilhado (menus, abas) |
StatefulShellModuleRoute |
Navegação com múltiplas pilhas (bottom nav) |
ShellModuleRoute
ShellModuleRoute(
builder: (context, state, child) => Scaffold(body: child),
routes: [
ChildRoute(path: '/user', child: (_, _) => const UserPage()),
ChildRoute(path: '/config', child: (_, _) => const ConfigPage()),
],
)
StatefulShellModuleRoute
StatefulShellModuleRoute(
builder: (context, state, shell) => BottomBarWidget(shell: shell),
routes: [
ModuleRoute(path: '/', module: HomeModule()),
ModuleRoute(path: '/profile', module: ProfileModule()),
],
)
AliasRoute
alias(from: '/cart/:id', to: '/order/:id');
Tanto /cart/123 quanto /order/123 renderizam a mesma tela.
📚 Detalhes: Rotas
🧩 API Declarativa (DSL)
Sintaxe fluente para definir rotas sem boilerplate:
final class AppModule extends Module {
@override
List<IRoute> routes() => [
child(child: (_, _) => const HomePage()),
module(module: AuthModule()),
alias(from: '/cart/:id', to: '/order/:id'),
shell(
builder: (_, _, child) => MainShell(child: child),
routes: [
child(path: '/dashboard', child: (_, _) => const DashboardPage()),
],
),
statefulShell(
builder: (_, _, shell) => BottomBarWidget(shell: shell),
routes: [
module(module: FeedModule()),
module(module: ProfileModule()),
],
),
];
}
| Helper | Retorna | Uso |
|---|---|---|
child() |
ChildRoute |
Telas simples |
module() |
ModuleRoute |
Submódulos |
alias() |
AliasRoute |
Caminhos alternativos |
shell() |
ShellModuleRoute |
Layouts compartilhados |
statefulShell() |
StatefulShellModuleRoute |
Múltiplas pilhas |
📚 Detalhes: API Declarativa
🔒 Guards
Controle de acesso a rotas com lógica condicional:
final class AuthGuard implements IGuard {
@override
FutureOr<String?> call(BuildContext context, GoRouterState state) async {
final isLoggedIn = await checkAuth();
return isLoggedIn ? null : '/login';
}
}
Aplique em rotas individuais ou propague para submódulos:
// Por rota
route('/', child: (_, _) => const HomePage(), guards: [AuthGuard()]);
// Propagação para todos os filhos
List<IRoute> routes() => propagateGuards(
guards: [AuthGuard()],
routes: [
module('/home', HomeModule()),
module('/profile', ProfileModule()),
],
);
📚 Detalhes: Guards
🛠️ Injeção de Dependência
final class HomeModule extends Module {
@override
void binds() {
i
..registerSingleton<ServiceRepository>(ServiceRepository())
..registerLazySingleton<ApiClient>(ApiClient.new);
}
}
Três formas de acessar:
final service = i.get<ServiceRepository>();
final service = Modugo.i.get<ServiceRepository>();
final service = context.read<ServiceRepository>();
📚 Detalhes: Injeção de Dependência
📡 Sistema de Eventos
Comunicação desacoplada entre módulos:
// Definir evento
final class UserLoggedInEvent {
final String userId;
UserLoggedInEvent(this.userId);
}
// Emitir
Event.emit(UserLoggedInEvent('user-123'));
// Ouvir
Event.i.on<UserLoggedInEvent>((event) {
print('Logou: ${event.userId}');
});
O Modugo emite RouteChangedEventModel automaticamente a cada navegação:
Event.i.on<RouteChangedEventModel>((event) {
print('Navegou para: ${event.location}');
});
📚 Detalhes: Eventos
🧰 Utilitários
AfterLayoutMixin
Executa código após o primeiro frame do widget:
class _MyScreenState extends State<MyScreen> with AfterLayoutMixin {
@override
Future<void> afterFirstLayout(BuildContext context) async {
context.read<HomeController>().loadData();
}
}
CompilerRoute
Validação e extração de parâmetros de rotas:
final route = CompilerRoute('/user/:id');
route.match('/user/42'); // true
route.extract('/user/42'); // {'id': '42'}
route.build({'id': '42'}); // '/user/42'
Logging
await Modugo.configure(module: AppModule(), debugLogDiagnostics: true);
📚 Detalhes: Utilitários | Extensions
📚 Documentação
Documentação completa disponível em MkDocs:
| Seção | Descrição |
|---|---|
| Primeiros Passos | Instalação e configuração |
| Módulos | Arquitetura modular |
| Rotas | Tipos de rotas e navegação |
| API Declarativa | DSL fluente para rotas |
| Transições | Animações de página |
| Injeção | GetIt e context extensions |
| Guards | Proteção de rotas |
| Eventos | Comunicação entre módulos |
| Extensions | Extensions de BuildContext, GoRouterState e Uri |
| Utilitários | AfterLayoutMixin, CompilerRoute, Logger |
| Migração | Guia v2 → v3 → v4 |
🤝 Contribuições
Pull requests e sugestões são bem-vindos! 💜
📜 Licença
MIT ©