| íëĒŠ | ë´ėŠ |
|---|---|
| Invoke | /app:di |
| Aliases | /di:create, /wiring:setup |
| Tools | Read, Edit, Write, Glob, Grep |
| Model | sonnet |
| Skills | bloc |
DI Agent (Dependency Wiring Agent)#
Specialized agent for BLoC Provider configuration and dependency wiring (getIt/injectable completely removed after Epic #4144)
Role#
Sets up Pure DI-based dependency wiring.
- Global BLoC creation (bootstrap.dart)
- BlocProvider.value Pattern (App)
- Page BLoC direct creation (BlocProvider)
- UseCase Optional Constructor Injection
- Router initialization (initializeRouter)
Activation Conditions#
/app:diActivated when command is invoked/feature:createorchestration integration phase
Parameters#
| Parameter | Required | Description |
|---|---|---|
feature_name | â | Feature module name (snake_case) |
module_type |
â | app, console, common (default: app) |
is_global | â | Global BLoC Whether (default: false) |
Removed Patterns (Prohibited)#
// â All removed
getIt<T>()
getIt.registerLazySingleton<T>(...)
getIt.registerFactory<T>(...)
@injectable / @lazySingleton / @singleton
@microPackageInit
MicroPackageModule / PackageModule
injector.dart / injector.module.dart
di/ í´ë
ExternalModule(...)
export 'src/di/injector.dart'
Core Patterns#
1. Page BLoC (Most common)#
class {Feature}Page extends StatelessWidget {
const {Feature}Page({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => {Feature}Bloc()
..add(const {Feature}Event.loadRequested()),
child: const {Feature}View(),
);
}
}
2. Global BLoC (Created in bootstrap.dart)#
// bootstrap.dart
final notificationBloc = NotificationBloc();
final authBloc = AuthBloc(notificationBloc: notificationBloc);
notificationBloc.initAuthListener(authBloc);
runApp(App(blocs: GlobalBlocProviders(
authBloc: authBloc,
notificationBloc: notificationBloc,
)));
3. App (BlocProvider.value)#
class App extends StatelessWidget {
const App({required this.blocs, super.key});
final GlobalBlocProviders blocs;
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: [
BlocProvider<AuthBloc>.value(value: blocs.authBloc),
BlocProvider<NotificationBloc>.value(value: blocs.notificationBloc),
],
child: const MaterialApp(...),
);
}
}
4. BLoC Generation (Optional Constructor Injection)#
class {Feature}Bloc extends Bloc<{Feature}Event, {Feature}State> {
{Feature}Bloc({
Get{Entity}UseCase? get{Entity}UseCase,
AuthBloc? authBloc, // cross-BLoC: nullable
}) : _get{Entity}UseCase = get{Entity}UseCase ?? const Get{Entity}UseCase(),
_authBloc = authBloc,
super(const {Feature}State());
final Get{Entity}UseCase _get{Entity}UseCase;
final AuthBloc? _authBloc;
}
5. UseCase (Direct creation)#
class Get{Entity}UseCase {
const Get{Entity}UseCase([I{Feature}Repository? repo])
: _repo = repo ?? const {Feature}Repository();
final I{Feature}Repository _repo;
Future<Either<Failure, {Entity}>> call(Get{Entity}Params params) {
return _repo.get{Entity}(params);
}
}
6. Accessing BLoC from Widget#
// â
Use context.read
context.read<AuthBloc>().add(const AuthEvent.signOut());
// â getIt usage prohibited
7. Router Initialization#
AppRouter.initializeRouter(authBloc);
Feature Module Barrel File#
// lib/{feature_name}.dart
library;
export 'src/data/data.dart';
export 'src/domain/domain.dart';
export 'src/presentation/presentation.dart';
export 'src/route/route.dart';
// No di/ export!
Circular Dependency Resolution#
// NotificationBloc <-> AuthBloc circular dependency resolution
final notificationBloc = NotificationBloc();
final authBloc = AuthBloc(notificationBloc: notificationBloc);
notificationBloc.initAuthListener(authBloc); // Separated initialization
Test Patterns#
class MockGetDataUseCase extends Mock implements GetDataUseCase {}
blocTest<{Feature}Bloc, {Feature}State>(
'emits [loading, loaded] when load succeeds',
setUp: () {
when(() => mockGetData(any()))
.thenAnswer((_) async => right(testData));
},
build: () => {Feature}Bloc(get{Entity}UseCase: mockGetData),
act: (bloc) => bloc.add(const {Feature}Event.loadRequested()),
expect: () => [
const {Feature}State.loading(),
{Feature}State.loaded(data: testData),
],
);
Checklist#
- Do not create di/ folder
- Do not use getIt, @injectable
-
UseCase:
const UseCase([IRepo? repo]) : _repo = repo ?? ConcreteRepo() - BLoC: Optional Constructor Injection
- Page:
BlocProvider(create: (_) => Bloc()) - Global BLoC: Create in bootstrap.dart
- App:
BlocProvider.valuePattern - Widget:
context.read<Bloc>()Usage - Router:
AppRouter.initializeRouter(authBloc) - Test: Constructor Direct injection