pushed

Scoped dependencies for go_router routes using get_it.

Enables automatic dependency injection and lifecycle management for route-specific dependencies in Flutter applications using go_router.

๐ŸŽฏ Features

  • Route-Scoped Dependencies - Register dependencies specific to individual routes
  • Automatic Lifecycle - Services are created when routes are entered and disposed when exited
  • Hierarchical Scopes - Support for nested routes with scope inheritance
  • Type-Safe - Full Dart type safety for dependency access
  • Easy Integration - Simple extensions that work seamlessly with go_router and get_it
  • Async Support - Both initialization and disposal support async operations
  • Zero Boilerplate - Minimal code to integrate into your app

๐Ÿ“ฆ Installation

Add this to your pubspec.yaml:

dependencies:
  pushed: ^0.2.1
  go_router: ^17.0.0
  get_it: ^9.0.0

Then run:

flutter pub get

๐Ÿš€ Quick Start

1. Create a ScopeObserver

final scopeObserver = ScopeObserver();

2. Add observer to GoRouter

GoRouter(
  observers: [scopeObserver],
  routes: [
    // your routes here
  ],
)

3. Register scoped dependencies

GoRoute(
  path: '/products',
  name: 'products',
  builder: (context, state) => const ProductsPage(),
).withScope(
  observer: scopeObserver,
  scopeInitializer: (getIt) {
    getIt.registerSingleton<ProductService>(ProductService());
  },
  scopeDisposer: (getIt) async {
    final service = getIt<ProductService>();
    await service.dispose();
  },
)

4. Access dependencies in your pages

class ProductsPage extends StatelessWidget {
  const ProductsPage({super.key});

  @override
  Widget build(BuildContext context) {
    final productService = GetIt.instance<ProductService>();
    return Scaffold(
      body: // use productService
    );
  }
}

๐Ÿ“š Complete Example

See the example app for a complete working example demonstrating:

  • Creating a ScopeObserver
  • Registering scoped dependencies
  • Accessing dependencies with GetIt
  • Automatic cleanup when routes are popped

Run the example:

cd example
flutter run

๐Ÿ’ก Scope Lifecycle

Navigate to route with scope
  โ†“
ScopeObserver detects route push
  โ†“
scopeInitializer called
  โ†“
Services registered in GetIt scope
  โ†“
Page can access via GetIt.instance<Service>()
  โ†“
Navigate away / route popped
  โ†“
scopeDisposer called
  โ†“
Services removed from GetIt
  โ†“
Memory freed

๐ŸŽฏ Best Practices

1. Always use scopeDisposer for cleanup

.withScope(
  observer: observer,
  scopeInitializer: (getIt) {
    getIt.registerSingleton<DatabaseService>(DatabaseService());
  },
  scopeDisposer: (getIt) async {
    await getIt<DatabaseService>().close();
  },
)
scopeInitializer: (getIt) {
  getIt.registerSingleton<UserService>(UserService());
  getIt.registerSingleton<AuthService>(AuthService());
  getIt.registerSingleton<PreferencesService>(PreferencesService());
}

3. Use hierarchical scopes for nested routes

GoRoute(
  path: '/products',
  builder: (context, state) => ProductsPage(),
  routes: [
    GoRoute(
      path: ':id',
      builder: (context, state) => ProductDetailPage(),
    ).withScope(
      observer: observer,
      scopeInitializer: (getIt) {
        // Can access parent scope services
        getIt.registerSingleton<ProductDetailService>(
          ProductDetailService(),
        );
      },
    ),
  ],
).withScope(
  observer: observer,
  scopeInitializer: (getIt) {
    getIt.registerSingleton<ProductService>(ProductService());
  },
)

๐Ÿงช Testing

Use resetAllScopes() in tests:

test('my test', () async {
  final router = createRouter();
  
  // Navigate and test
  // ...
  
  // Cleanup
  await router.resetAllScopes();
});

๐Ÿ“ˆ Performance

  • Minimal overhead - Scopes created/disposed only when needed
  • No global state pollution - Each scope is isolated
  • Efficient memory management - Automatic cleanup prevents leaks
  • Type-safe - Full Dart type checking at compile time

๐Ÿ› Troubleshooting

Service not found error

Problem: GetIt.get<MyService>() not found

Solution:

  • Ensure ScopeObserver is added to GoRouter.observers
  • Verify service is registered in scopeInitializer
  • Check that you've navigated to the route

Memory leaks

Problem: Services not being cleaned up

Solution:

  • Implement scopeDisposer callbacks
  • Ensure services implement proper cleanup
  • Use router.resetAllScopes() in tests

๐Ÿ“ Changelog

See CHANGELOG.md for release history.

๐Ÿค Contributing

Contributions are welcome! See CONTRIBUTING.md for guidelines.

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ’ฌ Support

For issues, questions, or suggestions, please open an issue on GitHub.


Made with โค๏ธ by Robson Silva with assistance from AI.

Libraries

pushed