У проєкті з 50+ сервісами та репозиторіями ручна реєстрація залежностей через GetIt перетворюється на хаос. injection_container.dart розростається до 500+ рядків, порядок реєстрації збивається, а при рефакторингу забувають оновлювати реєстрацію. Результат — StateError: No instance of type ApiService found у рантаймі. Ми стикалися з цим десятки разів і навчилися вирішувати проблему автоматично. На одному з проєктів ручна реєстрація забирала до 3 днів роботи на кожну нову фічу.
Налаштування injectable — кодогенератора поверх GetIt — скорочує ручний код на 70% та виключає помилки реєстрації. Ви просто пишете аннотації @injectable або @lazySingleton, запускаєте build_runner, і він генерує файл injection.config.dart. Все, DI чистий і декларативний. Це знижує трудозатрати на підтримку до 80%.
Як injectable спрощує управління залежностями?
Ручна реєстрація в GetIt не масштабується: при 50+ залежностях легко заплутатися в порядку, забути оновити при рефакторингу, а чужий injection_container часто перетворюється на "чорну скриньку". injectable усуває цю ручну працю — додав аннотацію до класу, запустив build_runner, файл оновився автоматично. Економія часу — до 2 годин на тиждень на підтримці DI. На практиці це означає, що розробник не відволікається на рутину і рідше допускає помилки.
Як налаштувати injectable у проєкті?
Базове налаштування займає 10–15 хвилин. Додайте залежності в pubspec.yaml:
dependencies: get_it: ^7.6.0 injectable: ^2.3.0 dev_dependencies: injectable_generator: ^2.4.0 build_runner: ^2.4.0 Створіть точку входу — файл із функцією ініціалізації:
import 'package:get_it/get_it.dart'; import 'package:injectable/injectable.dart'; import 'injection.config.dart'; final sl = GetIt.instance; @InjectableInit() Future<void> configureDependencies() => sl.init(); Аннотуйте сервіс, наприклад:
@lazySingleton class ApiService { final Dio _dio; ApiService(this._dio); } Запустіть генерацію: dart run build_runner build --delete-conflicting-outputs. Для постійної генерації використовуйте build_runner watch — він автоматично оновлює код при кожній зміні аннотацій.
Як працювати з оточеннями?
injectable підтримує @Environment аннотації — вбудована підтримка dev, staging, production без ручних умов. Приклад:
@dev @LazySingleton(as: ApiService) class MockApiService implements ApiService { ... } @prod @LazySingleton(as: ApiService) class RealApiService implements ApiService { ... } // Ініціалізація з оточенням: await configureDependencies(environment: Environment.prod); У тестах передаєте Environment.dev — моки підключаються автоматично. Жодних if в injection_container.
Як обробляти async-залежності?
Для асинхронної ініціалізації використовуйте @factoryMethod:
@singleton class DatabaseService { late final Database _db; @factoryMethod static Future<DatabaseService> create() async { final service = DatabaseService(); service._db = await openDatabase('app.db'); return service; } } injectable згенерує registerSingletonAsync, а configureDependencies() поверне Future. Не забудьте await перед runApp.
Чому виникає помилка 'No instance of type'?
Найчастіша причина — розробник додав новий клас з аннотацією, але забув запустити build_runner. Додаток компілюється зі старим injection.config.dart, новий клас залишається незареєстрованим. Рішення: додайте build_runner watch у процес розробки або налаштуйте CI-крок для перевірки актуальності згенерованого коду.
Порада щодо прискорення розробки
Використовуйте `build_runner watch` в окремому терміналі. Він автоматично перегенеровує код при зміні файлів з аннотаціями. Це економить час і запобігає помилкам.Порівняння: ручний GetIt vs Injectable
| Параметр | Ручний GetIt | Injectable |
|---|---|---|
| Об'єм коду | 1 файл на 300+ рядків | ~10 рядків + аннотації |
| Ризик помилок реєстрації | Високий (забули порядок) | Низький (кодогенерація) |
| Підтримка оточень | Ручна логіка | Вбудована через @Environment |
| Рефакторинг | Потрібно правити injection_container |
Достатньо змінити аннотацію |
| Тестування | Додаткові моки вручну | Легко переключити оточення |
Типові помилки при DI та їх вирішення
| Помилка | Причина | Рішення |
|---|---|---|
| No instance of type | Не запущено build_runner | Запустити build_runner або watch |
| Duplicate registration | Двічі зареєстровано один тип | Використовувати @singleton або @lazySingleton |
| Circular dependency | Неправильна архітектура | Розділити сервіси, використовувати фабрики |
| Environment mismatch | Неправильне оточення | Вказати Environment при ініціалізації |
Як ми налаштовуємо DI у вашому проєкті
Налаштування Dependency Injection — частина нашої стандартної архітектури Flutter-проєктів. Ми виконуємо її під ключ: встановлюємо та конфігуруємо залежності (get_it, injectable, build_runner), створюємо точку входу з підтримкою оточень, аннотуємо всі сервіси, репозиторії та фабрики, налаштовуємо async-залежності та фабричні методи, інтегруємо кодогенерацію в CI/CD (автоматичний запуск build_runner), мігруємо існуючий ручний injection_container на аннотації та документуємо архітектуру DI. Після налаштування команда отримує чітку структуру, яку легко масштабувати при додаванні нових фіч. Новий розробник розбирається в DI-шарі за 30 хвилин замість кількох годин.
Наш досвід — 5+ років розробки на Flutter, понад 30 завершених мобільних проєктів. Гарантуємо, що DI-шар буде стабільним і легко розширюваним. Зв'яжіться з нами, щоб обговорити задачу та отримати консультацію щодо архітектури вашого додатка. Замовте налаштування DI — і ми підберемо оптимальне рішення для вашого проєкту.
Робота займає 1–3 дні залежно від розміру проєкту. На новому проєкті — швидше, на існуючому з ручним DI — довше через міграцію та тестування коректності порядку реєстрацій. Результат: чиста, масштабована архітектура DI. Оцінимо ваш проєкт безкоштовно — просто напишіть.
Офіційна документація Injectable: pub.dev/packages/injectable







