JavaRush /Курсы /Модуль 4: Node.js, Next.js и Angular /Основы Standalone Components: создание, отличие от NgModu...

Основы Standalone Components: создание, отличие от NgModule

Модуль 4: Node.js, Next.js и Angular
13 уровень , 4 лекция
Открыта

1. Компоненты нового поколения

До сих пор мы работали с классическими Angular-компонентами, которые всегда требуют регистрации в NgModule. Теперь пришло время познакомиться с более современным подходом — Standalone Components.

Если вы только начинаете знакомство с Angular, то слово Standalone может звучать как что-то из мира фильмов про супергероев. На самом деле, Standalone Components — это компоненты, которые могут существовать и использоваться без объявления их в каком-либо NgModule. Это нововведение появилось в Angular 14, а с версии 16 оно стало стандартом для большинства новых проектов.

Зачем это нужно?

  • Проще стартовать новый проект. Не нужно создавать и поддерживать NgModule для каждого компонента.
  • Меньше шаблонного кода, меньше ошибок с импортами и декларациями.
  • Упрощает рефакторинг и повторное использование компонентов между проектами.
  • Более быстрые загрузки и улучшенная поддержка ленивой загрузки (lazy loading).

Устройство классического компонента

Вот шаги работы с обычными компонентами:

  1. Создаём компонент (например, TaskListComponent).
  2. Обязательно добавляем его в массив declarations какого-либо модуля (обычно AppModule).
  3. Если хотим использовать его в другом модуле — не забудьте про exports и imports в соответствующем NgModule.
  4. Если забыли добавить компонент в нужный модуль — получите ошибку "Component is not part of any NgModule" (Компонент не является частью какого-либо NgModule) при запуске приложения.

Вот пример классического компонента и его объявления в модуле:

// task-list.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-task-list',
  template: `<h2>Список задач</h2>`
})
export class TaskListComponent {}
// app.module.ts (пример модуля, где объявляется классический компонент)
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { TaskListComponent } from './task-list.component'; // Импортируем наш компонент

@NgModule({
  declarations: [TaskListComponent], // <--- Объявляем (регистрируем) компонент здесь!
  imports: [BrowserModule],
  bootstrap: [TaskListComponent] // Или AppComponent, если это корневой
})
export class AppModule {}

Вопрос: А если забыть добавить компонент в declarations?
Ответ: Angular вас не пощадит — получите ошибку при запуске, потому что не будет знать о его существовании.

2. Standalone Component: синтаксис и создание

С появлением Standalone Components всё стало проще. Теперь можно создать компонент, который не требует объявления в NgModule.

Как создать Standalone Component?

Через CLI:

ng generate component task-list --standalone

Или покороче:

ng g c task-list --standalone

Результат:
CLI сгенерирует компонент с новым параметром standalone: true в декораторе @Component.

// task-list.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-task-list',
  standalone: true, // ← вот оно!
  template: `<h2>Список задач</h2>`
})
export class TaskListComponent {}

Обратите внимание:
- Нет необходимости добавлять компонент в declarations какого-либо модуля.
- Можно использовать компонент напрямую в точке входа приложения (bootstrapApplication).

3. Использование Standalone Components в приложении

Новый способ запуска приложения

С появлением Standalone Components, Angular предлагает новый подход к запуску приложения — без NgModule! Вместо bootstrapModule(AppModule), теперь можно использовать bootstrapApplication().

// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { TaskListComponent } from './task-list.component';

bootstrapApplication(TaskListComponent)
  .catch(err => console.error(err));

Вуаля! Ваше приложение стартует с компонента, который даже не знает, что такое NgModule.

Добавление других Standalone Components

Если у вас есть ещё один Standalone Component (например, TaskItemComponent), вы можете импортировать его прямо в imports другого компонента:

// task-item.component.ts
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-task-item',
  standalone: true,
  template: `<li>{{ task }}</li>`
})
export class TaskItemComponent {
  @Input() task = '';
}
// task-list.component.ts
import { Component } from '@angular/core';
import { TaskItemComponent } from './task-item.component';

@Component({
  selector: 'app-task-list',
  standalone: true,
  imports: [TaskItemComponent], // ← прямо здесь!
  template: `
    <h2>Список задач</h2>
    <ul>
      <app-task-item *ngFor="let t of tasks" [task]="t"></app-task-item>
    </ul>
  `
})
export class TaskListComponent {
  tasks = ['Погладить кота', 'Сделать домашку', 'Посмотреть сериал'];
}

Ключевой момент:
Всё, что раньше импортировалось через NgModule, теперь импортируется непосредственно в компонент через свойство imports.

4. Импорт Angular- и сторонних модулей в Standalone Component

Всё хорошо, но как же быть с Angular-модулями вроде CommonModule (чтобы работали *ngIf, *ngFor), или сторонними библиотеками?

Просто добавьте их в imports:

import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-my-list',
  standalone: true,
  imports: [CommonModule],
  template: `
    <ul>
      <li *ngFor="let item of items">{{ item }}</li>
    </ul>
  `
})
export class MyListComponent {
  items = ['Angular', 'React', 'Vue'];
}

Факт:
Теперь CommonModule и любые другие Angular-модули (например, FormsModule, ReactiveFormsModule) можно импортировать непосредственно в Standalone Component.

5. Сравнение: Standalone Component vs. NgModule

Критерий Standalone Component Классический через NgModule
Объявление
standalone: true
в декораторе
В массиве
declarations
модуля
Импорт других компонентов Через
imports
в декораторе компонента
Через
imports
и
exports
модуля
Использование Angular-модулей Через
imports
компонента
Через
imports
модуля
Bootstrap приложения Через
bootstrapApplication()
Через
bootstrapModule()
Ленивые модули (Lazy Loading) Упрощён, не требует отдельного модуля Требует отдельного
NgModule
IDE-подсказки Отлично поддерживается Отлично поддерживается
Совместимость Angular
14+
Angular
2+

Основные отличия:

  • Standalone Components не требуют NgModule вообще.
  • Импорт других компонентов, директив и пайпов — прямо в декораторе компонента.
  • Упрощённая иерархия, меньше файлов, меньше ошибок с импортами.
  • Отлично подходят для новых проектов и миграции старых (постепенно).

6. Практика: Развиваем мини-приложение "Список задач"

Давайте добавим форму для создания новых задач, используя Standalone Components и Angular Forms.

Шаг 1. Импортируем FormsModule

import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-task-list',
  standalone: true,
  imports: [CommonModule, FormsModule],
  template: `
    <h2>Список задач</h2>
    <form (ngSubmit)="addTask()">
      <input [(ngModel)]="newTask" name="task" required>
      <button type="submit">Добавить</button>
    </form>
    <ul>
      <li *ngFor="let t of tasks">{{ t }}</li>
    </ul>
  `
})
export class TaskListComponent {
  tasks = ['Погладить кота', 'Сделать домашку', 'Посмотреть сериал'];
  newTask = '';

  addTask() {
    if (this.newTask.trim()) {
      this.tasks.push(this.newTask.trim());
      this.newTask = '';
    }
  }
}

Шаг 2. Запуск Standalone Component

// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { TaskListComponent } from './task-list.component';

bootstrapApplication(TaskListComponent)
  .catch(err => console.error(err));

Всё! Ваше приложение работает без единого NgModule.

7. Особенности и ограничения Standalone Components

Особенности

  • Можно постепенно мигрировать старые проекты: Standalone Components и NgModule могут сосуществовать.
  • Можно использовать Standalone Components внутри NgModule (но не наоборот).
  • Поддерживают все возможности Angular: DI, роутинг, формы, пайпы, директивы.

Ограничения

  • Некоторые сторонние библиотеки могут ещё не поддерживать Standalone Components (ситуация быстро меняется).
  • Для сложных приложений с множеством повторно используемых компонентов иногда удобнее группировать их в NgModule (но это уже дело вкуса и архитектуры).

Факт:
Angular Router с версии 14 поддерживает ленивую загрузку Standalone Components без создания отдельного модуля.

8. Типичные ошибки при работе со Standalone Components

Ошибка №1: Забыли указать standalone: true.
Компонент не будет работать как Standalone, если этот параметр не указан. Angular попытается найти его в NgModule и выдаст ошибку.

Ошибка №2: Не импортировали CommonModule, а используете *ngIf или *ngFor.
В Standalone Component всегда нужно явно импортировать нужные Angular-модули через imports, иначе получите ошибку вида: "Can't bind to 'ngForOf' since it isn't a known property of 'li'".

Ошибка №3: Путают imports компонента и NgModule.
В Standalone Component импортируйте всё в массив imports внутри декоратора, а не в NgModule.

Ошибка №4: Забыли добавить FormsModule для работы с формами.
В классическом подходе FormsModule часто импортируется в AppModule, но в Standalone Component его нужно добавить вручную.

Ошибка №5: Не обновили Angular CLI или используете старую версию Angular.
Standalone Components поддерживаются только с Angular 14+. Если у вас старая версия — обновитесь, иначе ничего не получится.

3
Опрос
Введение в Angular, 13 уровень, 4 лекция
Недоступен
Введение в Angular
Введение в Angular
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ