modularity_injectable

pub package

Optional integration package that connects injectable + GetIt code generation with the Modularity framework.

Note: This package is entirely optional. The core Modularity framework works perfectly with manual binds/exports registration. Use this adapter only if you prefer auto-wiring via injectable.

Features

  • GetItBinder — a Binder implementation backed by scoped GetIt instances
  • ModularityInjectableBridge — helper to invoke injectable-generated functions inside binds/exports
  • BinderGetIt — GetIt proxy that resolves dependencies through Modularity rules (local/imports/parent)
  • modularityExportEnv — environment constant to mark dependencies for export

Installation

dependencies:
  modularity_injectable: ^0.1.1

dev_dependencies:
  build_runner: ^2.4.0
  injectable_generator: ^2.4.0

Quick Start

1. Configure your app root

ModularityRoot(
  binderFactory: const GetItBinderFactory(),
  child: MyApp(),
);

2. Create injectable configuration

// lib/di/auth_injectable.dart
import 'package:get_it/get_it.dart';
import 'package:injectable/injectable.dart';

@InjectableInit(initializerName: 'configureAuthInternal', asExtension: false)
GetIt configureAuthInternal(GetIt getIt) => $initGetIt(getIt);

/// Same generated graph, but we forward the [environmentFilter]
/// so Modularity can limit exports.
@InjectableInit(initializerName: 'configureAuthExports', asExtension: false)
GetIt configureAuthExports(
  GetIt getIt, {
  EnvironmentFilter? environmentFilter,
}) =>
    $initGetIt(
      getIt,
      environmentFilter: environmentFilter,
    );

Why two functions? Both are generated by injectable. The exports variant simply forwards the environmentFilter argument so that ModularityInjectableBridge.configureExports can inject ModularityExportOnly and keep the public scope limited to explicitly marked services.

3. Annotate your dependencies

@LazySingleton()
class AuthRepositoryImpl implements AuthRepository { ... }

// Pick whichever style you prefer:

// 1) Environment name (works well when you already list multiple envs)
@LazySingleton(env: [modularityExportEnvName])
class AuthService { ... }

// 2) Annotation sugar (for single-purpose modules)
@modularityExportEnv
@LazySingleton()
class AuthController { ... }

4. Wire up your module

class AuthModule extends Module {
  @override
  void binds(Binder i) {
    ModularityInjectableBridge.configureInternal(i, configureAuthInternal);
  }

  @override
  void exports(Binder i) {
    ModularityInjectableBridge.configureExports(i, configureAuthExports);
  }
}

How It Works

  • configureInternal registers all dependencies into the private scope
  • configureExports registers only dependencies marked with env: [modularityExportEnvName] (or @modularityExportEnv) into the public scope
  • This preserves Modularity's strict module boundaries while letting injectable generate the wiring

Manual Alternative

If you prefer explicit registration without code generation, simply use the standard approach:

class AuthModule extends Module {
  @override
  void binds(Binder i) {
    i.singleton<AuthRepository>(() => AuthRepositoryImpl());
  }

  @override
  void exports(Binder i) {
    i.singleton<AuthService>(() => AuthService(i.get()));
  }
}

See the main Modularity documentation for more details.