JavaRush /Курсы /Модуль 4: Node.js, Next.js и Angular /Ленивая загрузка модулей/компонентов и структура Angular-...

Ленивая загрузка модулей/компонентов и структура Angular-приложения, best practices

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

1. Как работает ленивая загрузка модулей в Angular

Давайте представим, что Angular-приложение — это супермаркет, а ваши пользователи — покупатели. Если при первом входе вы заставите их ждать, пока откроются ВСЕ отделы (даже те, куда они никогда не зайдут), они вряд ли будут в восторге. Ленивая загрузка — это когда вы открываете только главный вход и ближайшие витрины, а остальные отделы "разворачиваете" только тогда, когда покупатель туда реально заходит.

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

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

Немного теории

В Angular ленивая загрузка реализуется на уровне feature-модулей (фичевых модулей). Вы создаёте отдельный модуль для функционального раздела (например, AdminModule, UserModule), настраиваете для него собственные маршруты, а в основном роутинге приложения указываете, что этот модуль должен загружаться только при обращении к определённому пути.

Пример: базовая настройка ленивой загрузки

Создаём feature-модуль

ng generate module admin --route admin --module app.module

Эта команда не только создаст модуль, но и сразу добавит его в маршруты с ленивой загрузкой!

Как выглядит запись в app-routing.module.ts

const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
  },
  // другие маршруты...
];

Что тут происходит?
Когда пользователь заходит по адресу /admin, Angular динамически загружает (импортирует) модуль AdminModule.
До этого момента JS-код этого модуля вообще не попадает в главный бандл!

Как это выглядит в браузере

  • Открываете / — грузится только основной бандл.
  • Открываете /admin — в консоли (Network) видите, что подгружается отдельный чанк (файл JS), отвечающий за AdminModule.

Визуальная схема

[Главный бандл] ---запрос---> [HomeComponent, AboutComponent]
      |
      | (пользователь кликает на "Admin")
      |
      +---запрос---> [admin.*.js: AdminModule, AdminComponent, ...]

2. Ленивая загрузка Standalone-компонентов (Angular 15+)

С появлением Standalone-компонентов (Standalone Components) в Angular 15 стало возможным лениво загружать не только модули, но и отдельные компоненты! Это особенно удобно, если вы строите приложение без NgModules (или хотите "по-современному").

Пример: ленивый Standalone-компонент

Создаём Standalone-компонент

ng generate component lazy-page --standalone

Добавляем маршрут с ленивой загрузкой компонента

const routes: Routes = [
  {
    path: 'lazy',
    loadComponent: () => import('./lazy-page/lazy-page.component')
      .then(c => c.LazyPageComponent)
  }
];

Обратите внимание:
Вместо loadChildren используем loadComponent.
Angular загрузит компонент только при переходе на /lazy.

Когда использовать ленивую загрузку компонентов?

  • Когда у вас небольшие разделы/страницы, которые не требуют отдельного модуля.
  • Когда вы хотите максимально упростить структуру приложения.
  • Для диалогов, больших форм, "тяжёлых" страниц, которые редко используются.

3. Организация структуры Angular-приложения: best practices

Почему структура имеет значение?

  • Лёгкая масштабируемость: проект растёт — структура не рассыпается.
  • Удобство навигации по коду для команды (и для вас спустя месяц!).
  • Простота внедрения ленивой загрузки и разделения ответственности.

Типичная структура среднего приложения

src/
  app/
    core/            # Сервисы, singleton-логика, глобальные guard-ы
    shared/          # Переиспользуемые компоненты, pipes, директивы
    features/        # Фичевые модули или standalone-компоненты
      admin/
        admin.module.ts
        admin-routing.module.ts
        pages/
        components/
      user/
        ...
    app-routing.module.ts
    app.component.ts
    ...
  assets/
  environments/

Краткое описание

  • core/ — глобальные singleton-сервисы, глобальные guard-ы, перехватчики (interceptors), глобальные утилиты.
  • shared/ — переиспользуемые компоненты (кнопки, инпуты), pipes, директивы, которые не зависят от бизнес-логики.
  • features/ — разделы приложения, каждый из которых может быть лениво загружен.
  • app-routing.module.ts — центральное место для настройки маршрутов и ленивой загрузки.

Особенности для Standalone-подхода

Если вы строите приложение на Standalone-компонентах, структура может быть чуть проще:

src/
  app/
    core/
    shared/
    pages/
      home/
        home.component.ts
      admin/
        admin.component.ts
      ...
    app.routes.ts
    app.component.ts

4. Практика: добавляем ленивую загрузку в учебное приложение

Давайте продолжим развивать наше учебное приложение (например, список задач с админкой).

Генерируем модуль и компонент для админки

ng generate module admin --route admin --module app.module
ng generate component admin/dashboard --module=admin

Добавляем ленивую загрузку в маршруты

В app-routing.module.ts:

const routes: Routes = [
  {
    path: 'admin',
    loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule)
  },
  // остальные маршруты
];

В admin-routing.module.ts:

const routes: Routes = [
  { path: '', component: DashboardComponent }
];

Проверяем результат

  • Собираем приложение.
  • Открываем / — код админки не грузится.
  • Открываем /admin — загружается дополнительный JS-файл.

Добавляем ленивый Standalone-компонент

ng generate component about-page --standalone

В app-routing.module.ts или app.routes.ts:

const routes: Routes = [
  {
    path: 'about',
    loadComponent: () => import('./about-page/about-page.component').then(c => c.AboutPageComponent)
  }
];

5. Полезные нюансы

Особенности и ограничения ленивой загрузки

  • Ленивая загрузка работает только для маршрутов. Нельзя лениво загрузить просто сервис или pipe — только модули/компоненты, связанные с маршрутом.
  • Сервисы, предоставленные в лениво загружаемом модуле, по умолчанию изолированы от основного инжектора (если не указан providedIn: 'root'). Это позволяет делать, например, отдельные сессии для админки и пользователя.
  • Guard-ы, резолверы и другие сервисы также могут быть определены в ленивых модулях — они будут работать только внутри этого раздела.
  • Пути в ленивых модулях всегда относительно своего корня! Не забывайте это при настройке вложенных маршрутов.

Как понять, что ленивая загрузка работает?

  • В девелоперских инструментах браузера (вкладка Network) при переходе на ленивый маршрут должен загружаться новый JS-файл.
  • В отчёте сборки (например, после ng build --stats-json и анализа через Webpack Bundle Analyzer) видно, что код разделён на чанки.
  • Если всё приложение грузится одним файлом — что-то пошло не так: проверьте конфигурацию маршрутов!

Best practices по структуре и ленивой загрузке

  • Делите приложение на feature-модули/standalone-компоненты по бизнес-логике, а не по техническим признакам.
  • Используйте ленивую загрузку для крупных разделов, которые не нужны сразу при старте. Например: админка, личный кабинет, разделы для разных ролей.
  • Переиспользуемые компоненты и сервисы держите в shared/core, а не в feature-модулях. Это ускоряет старт и предотвращает дублирование кода.
  • Старайтесь не делать слишком глубокую вложенность модулей — это усложняет навигацию и сборку.
  • Документируйте структуру проекта и правила разделения кода для команды.
  • Проверяйте результат ленивой загрузки после каждой крупной рефакторизации!
  • Не забывайте о preloading-стратегиях. Angular поддерживает автоматическую подгрузку ленивых модулей "на фоне" после старта приложения (PreloadAllModules), если вы хотите ускорить переходы без потери скорости старта.

6. Типичные ошибки и подводные камни

Ошибка №1: Неправильный путь к модулю или компоненту в loadChildren/loadComponent.
Если вы опечатались или переместили файл, Angular не найдёт модуль и выдаст ошибку при переходе по маршруту. Проверьте путь и экспортируемое имя класса.

Ошибка №2: Попытка лениво загрузить модуль без собственного роутинга.
Лениво загружаемый модуль должен иметь свой собственный RoutingModule или хотя бы массив маршрутов. Иначе при переходе по пути будет пусто.

Ошибка №3: Дублирование сервисов из-за разных инжекторов.
Если сервис предоставлен только в ленивом модуле (не в providedIn: 'root'), то экземпляры будут разные для каждого модуля. Это может привести к неожиданному поведению — например, разные "корзины" покупок в разных разделах.

Ошибка №4: Загрузка всего приложения в одном бандле.
Если вы случайно импортируете ленивый модуль в основной модуль (например, через imports: [AdminModule] в AppModule), он перестаёт быть ленивым! Проверяйте, что ленивые модули только в маршрутах.

Ошибка №5: Переиспользование компонентов между ленивыми и eagerly-загружаемыми модулями без shared-модуля/папки.
Это может привести к "дублирующимся" копиям компонента и ошибкам DI. Для переиспользования всегда выносите общий код в shared.

1
Задача
Модуль 4: Node.js, Next.js и Angular, 18 уровень, 9 лекция
Недоступна
Многостраничный сайт с базовой маршрутизацией
Многостраничный сайт с базовой маршрутизацией
1
Задача
Модуль 4: Node.js, Next.js и Angular, 18 уровень, 9 лекция
Недоступна
Страница пользователя с динамическим параметром id и навигацией по профилям
Страница пользователя с динамическим параметром id и навигацией по профилям
1
Задача
Модуль 4: Node.js, Next.js и Angular, 18 уровень, 9 лекция
Недоступна
Фильтрация и управление маршрутами через query-параметры
Фильтрация и управление маршрутами через query-параметры
1
Задача
Модуль 4: Node.js, Next.js и Angular, 18 уровень, 9 лекция
Недоступна
Защищённые маршруты и Guard для авторизации
Защищённые маршруты и Guard для авторизации
1
Задача
Модуль 4: Node.js, Next.js и Angular, 18 уровень, 9 лекция
Недоступна
Продвинутая маршрутизация с lazy loading и wildcard-страницей
Продвинутая маршрутизация с lazy loading и wildcard-страницей
3
Опрос
Динамические параметры маршрута, 18 уровень, 9 лекция
Недоступен
Динамические параметры маршрута
Динамические параметры маршрута
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ