Что такое модули в Angular?

Модули в Angular — это логические контейнеры, которые группируют компоненты, директивы, пайпы и сервисы, объединяя их в функциональные блоки. Каждый Angular-приложение как минимум состоит из одного модуля — AppModule. Модули оформляются как классы с декоратором @NgModule, который сообщает Angular, какие элементы входят в модуль, что следует экспортировать и какие зависимости подключать.

Модули позволяют:

  • Разделять код на независимые блоки;

  • Реализовать lazy loading;

  • Повторно использовать функциональность;

  • Изолировать зависимости;

  • Упростить масштабирование и поддержку приложения.

1. Синтаксис NgModule

Модуль — это класс, помеченный декоратором @NgModule.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { UserComponent } from './user.component';
@NgModule({
declarations: \[UserComponent\],
imports: \[CommonModule\],
exports: \[UserComponent\]
})
export class UserModule {}

2. Основные свойства @NgModule

  • declarations: Компоненты, директивы и пайпы, принадлежащие модулю.

  • imports: Другие модули, чьи публичные элементы (через exports) нужны в этом модуле.

  • exports: Элементы, которые можно использовать в других модулях, импортирующих текущий.

  • providers: Сервисы и другие зависимости, создаваемые для DI.

  • bootstrap: Компонент, с которого начинается загрузка приложения (используется только в корневом модуле).

Пример:

@NgModule({
declarations: \[AppComponent\],
imports: \[BrowserModule\],
providers: \[\],
bootstrap: \[AppComponent\]
})
export class AppModule {}

3. Типы модулей в приложении

3.1. Корневой модуль (AppModule)

  • Обязательный;

  • Запускается первым;

  • Содержит bootstrap — корневой компонент.

Файл: app.module.ts

@NgModule({
declarations: \[AppComponent\],
imports: \[BrowserModule, AppRoutingModule\],
bootstrap: \[AppComponent\]
})
export class AppModule {}

3.2. Feature-модули

  • Представляют функциональные блоки (например, UserModule, DashboardModule);

  • Могут подключаться напрямую или через lazy loading;

  • Обычно содержат свои компоненты, роутинг, сервисы.

@NgModule({
declarations: \[UserProfileComponent\],
imports: \[CommonModule\],
})
export class UserModule {}

3.3. Shared-модуль (SharedModule)

  • Хранит общие компоненты, директивы и пайпы, которые используются во многих местах;

  • Импортируется в другие модули, но сам не должен импортировать CoreModule.

@NgModule({
declarations: \[ButtonComponent, CapitalizePipe\],
exports: \[ButtonComponent, CapitalizePipe\],
imports: \[CommonModule\]
})
export class SharedModule {}

3.4. Core-модуль (CoreModule)

  • Используется для глобальных singleton-сервисов (auth, API, interceptors);

  • Импортируется только в AppModule;

  • Может реализовать forRoot()-паттерн для управления синглтонами.

@NgModule({
providers: \[AuthService, LoggerService\],
imports: \[CommonModule\]
})
export class CoreModule {}

4. CommonModule vs BrowserModule

  • BrowserModule используется только в AppModule.

  • CommonModule используется во всех остальных модулях (даёт директивы вроде *ngIf, *ngFor).

5. Lazy loading модулей

Позволяет загружать модули только при необходимости (по маршруту). Используется в роутинге:

const routes: Routes = \[
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
}
\];

AdminModule не будет загружен, пока пользователь не перейдёт на /admin.

6. Пример структуры модуля

src/app/
├── features/
 └── orders/
 ├── components/
 ├── services/
 ├── orders-routing.module.ts
 ├── orders.module.ts
@NgModule({
declarations: \[OrderListComponent, OrderDetailComponent\],
imports: \[CommonModule, OrdersRoutingModule\],
providers: \[OrdersService\]
})
export class OrdersModule {}

7. forRoot() и forChild() паттерны

Используются для передачи конфигураций или синглтонов:

@NgModule({
providers: \[LoggingService\]
})
export class LoggingModule {
static forRoot(): ModuleWithProviders<LoggingModule> {
return {
ngModule: LoggingModule,
providers: \[LoggingService\]
};
}
}

В AppModule:

imports: \[LoggingModule.forRoot()\]

8. Взаимодействие модулей

Если модуль A экспортирует компонент X, и модуль B хочет использовать X, он должен:

  • Импортировать A

  • X должен быть в A → exports

@NgModule({
declarations: \[X\],
exports: \[X\]
})
export class ModuleA {}
@NgModule({
imports: \[ModuleA\]
})
export class ModuleB {}

9. Рекомендации по организации модулей

  • Используйте feature-модули для каждой бизнес-функции;

  • Создавайте отдельные модули для роутинга (auth-routing.module.ts);

  • Используйте shared/core для повторного использования;

  • Не импортируйте SharedModule в CoreModule;

  • Следите за изоляцией: сервисы в Core, UI-компоненты в Shared;

  • Применяйте lazy loading для разделения бандлов.

10. Standalone компоненты (Angular 14+)

С появлением Standalone компонентов возможно отказаться от NgModule в ряде случаев.

Пример:

@Component({
standalone: true,
selector: 'app-login',
templateUrl: './login.component.html',
imports: \[FormsModule, CommonModule\]
})
export class LoginComponent {}

Можно подключать в роутинг:

{
path: 'login',
component: LoginComponent
}

Несмотря на поддержку Standalone компонентов, NgModule всё ещё актуален в архитектуре крупных приложений.