Flutter Monorepo & Dependency Injection
Tags: flutter, dart, tutorial, mobile
Published: 2023-10-01 16:47:42

I described dependency inversion and a way to use in dart/flutter in [this article](https://dev.to/mattia/mastering-dependency-injection-in-flutter-13bh). In this post I will use the same concepts and libraries.

## Monorepo
Monorepo refers to the practice of software development in which all components of an application or system are maintained within a single repository. A good article that describes well what it is, pros and cons is the following: [monorepo.tools](https://monorepo.tools). 
In the case of a flutter application an excellent monorepo manager is [Melos](https://melos.invertase.dev/), [here](https://medium.com/flutter-community/managing-multi-package-flutter-projects-with-melos-c8ce96fa7c82) a tutorial on how to create and manage it.

## A concrete use case
![UML](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7jy5h8grjr55t3yxggpy.png)

Suppose our application is a social app and we need to manage posts and users. The application is divided into packages where each package contains views and logics to manage a specific section of the application (users, posts, ...). _Route_ is defined within the `core` package. At this point each package defines its routes which will then be displayed in the _sidebar_ (see uml). The result is as follows:
- The abstract class _Route_ is in core;
- Its implementations are in different packages (_PostRoute_, _UserRoute_, ...).

## Implementation
This can be the folder structure,
```
app
  - lib
    ...
  - pubspec.yaml

modules
  - core
      - pubspec.yaml
      ...
  - user
      - pubspec.yaml
      ...
  - post
      - pubspec.yaml
      ...
```

where the various `pubspec.yaml` will look like:

```yaml
## app
dependencies:
  core: 
    path: ../modules/core
  user:
    path: ../modules/user
  post:
    path: ../modules/post
```

```yaml
## user
dependencies:
  core: 
    path: ../core
```

```dart
// app code
@Injectable(as: Navigation)
class AppNavigation implements Navigation {
  @override
  List<Route> routes = [UsersRoute()];
}

// core code
@injectable  
class SideBarMenu extends StatelessWidget {
  const SideBarMenu(this.navigation);

  final Navigation navigation;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: navigation.routes
          .map(
            (r) => Link(
              url: r.url,
              child: Text(r.name),
            ),
          )
          .toList(),
    );
  }
}

abstract class Navigation {
  List<Route> get routes;
}

abstract class Route {
  String get url;
  String get name;
  Widget view();
}

// post package
class PostsRoute implements Route {
  String url => "posts";
  String name => "Posts";
  Widget view => Container();
}
```

Each package defines a [micropackage](https://pub.dev/packages/injectable#including-micropackages-and-external-modules) (`core`, `user`, `posts`). Additionally in `core` we define getIt and export it for the other modules.

```dart
// only in core
GetIt getIt = GetIt.instance;

// every package
@InjectableInit.microPackage()
initMicroPackage() {} 
```

In `app` we init the injection and register the various micro packages. 

```dart
@InjectableInit(
    initializerName: 'init',
    preferRelativeImports: true,
    asExtension: false, 
    // packages
    externalPackageModulesBefore: [
      ExternalModule(CorePackageModule),
      ExternalModule(UserPackageModule),
      ExternalModule(PostPackageModule),
    ])
FutureOr<void> configureInjection() => init();
```

In this case all packages were registered (in order) with the method `externalPackageModulesBefore` but there are three properties that can be used (in order of registration): 1. `externalPackageModulesBefore`, 2. `externalPackageModules`, 3. `externalPackageModulesAfter`. 

## Conclusion
This concludes the article on Monorepo & Dependency Injection.

For more information on micropackage I recommend reading [injectable package](https://pub.dev/packages/injectable#including-micropackages-and-external-modules).