Что такое tree-shakable providers?angular-69

Tree-Shakable Providers — это современный способ регистрации сервисов в Angular, который позволяет сборщику (Webpack/Rollup) исключать неиспользуемый код из финального бандла через механизм tree-shaking.


Проблема традиционных провайдеров

Классический способ регистрации сервисов:

@NgModule({
  providers: [MyService] // или { provide: MyService, useClass: MyService }
})
export class AppModule {}

Недостатки:

  1. Сервис остается в бандле, даже если нигде не используется
  2. Сложность определения точного места использования
  3. Невозможность оптимизации на этапе сборки

Как работают Tree-Shakable Providers

Angular предоставляет два современных подхода:

1. Декоратор @Injectable с providedIn

@Injectable({
  providedIn: 'root' // или конкретный модуль
})
export class MyService {}

Принцип работы:

  • Сервис включается в бандл только если импортируется хотя бы одним компонентом/сервисом
  • Angular создает одно инстанс сервиса на указанный scope (root/module)

2. Функция provide

export const APP_CONFIG = new InjectionToken<Config>('app.config');

bootstrapApplication(AppComponent, {
  providers: [
    provide(MyService, {
      useClass: MyServiceImpl
    }),
    { provide: APP_CONFIG, useValue: config }
  ]
});

Ключевые преимущества

  1. Автоматическое tree-shaking:

    • Неиспользуемые сервисы исключаются из финального бандла
    • Пример: сервис аналитики, используемый только в AdminModule, не попадет в бандл если пользователь не зашел в админку
  2. Улучшенная инжекция зависимостей:

    • Более прозрачная система DI
    • Явное указание области видимости сервиса
  3. Оптимизация производительности:

    • Меньший размер бандла
    • Более быстрая загрузка приложения

Практический пример

До (традиционный подход):

@NgModule({
  providers: [LoggerService] // Всегда в бандле
})
export class AppModule {}

@Component(...)
export class MyComponent {
  constructor(private logger: LoggerService) {} // Используется
}

После (tree-shakable):

@Injectable({ providedIn: 'root' })
export class LoggerService {} // Только если используется

// Если ни один компонент не инжектит LoggerService - его не будет в бандле

Особенности реализации

  1. Условия для tree-shaking:

    • Сервис должен быть помечен как @Injectable()
    • Должен использовать ESM-импорты (import/export)
    • В tsconfig.json: "module": "esnext"
  2. Когда не сработает:

    • Сервис используется в шаблонах через DI (редкий случай)
    • Код вызывает сервис динамически (например, через injector.get())
  3. Scope варианты:

    • providedIn: 'root' - Singleton на все приложение
    • providedIn: MyModule - Локальный для модуля
    • providedIn: 'platform' - Для мульти-приложений

Резюмируем

Tree-Shakable Providers — это:

  1. Современный стандарт регистрации сервисов в Angular
  2. Оптимизация бандла через исключение неиспользуемого кода
  3. Простота внедрения — достаточно добавить @Injectable({providedIn: 'root'})

Используйте этот подход для:

  • Всех новых сервисов
  • Библиотек (особенно важно для npm-пакетов)
  • Кейсов где критичен размер бандла

Переход на tree-shakable providers может уменьшить размер вашего бандла на 10-30% в зависимости от количества неиспользуемых сервисов!