Разделение кода на уровне маршрута в Angular

Повысьте производительность вашего приложения, используя разделение кода на уровне маршрута!

В этом посте объясняется, как настроить разделение кода на уровне маршрута в приложении Angular, что может уменьшить размер пакета JavaScript и значительно улучшить время взаимодействия .

Примеры кода из этой статьи вы можете найти на GitHub . Пример нетерпеливой маршрутизации доступен в ветке нетерпеливых . Пример разделения кода на уровне маршрута находится в ленивой ветке .

Почему разделение кода имеет значение

Постоянно растущая сложность веб-приложений привела к значительному увеличению объема JavaScript, передаваемого пользователям. Большие файлы JavaScript могут заметно задерживать интерактивность, поэтому это может быть дорогостоящим ресурсом, особенно на мобильных устройствах.

Самый эффективный способ сократить пакеты JavaScript без ущерба для функций ваших приложений — это агрессивное разделение кода.

Разделение кода позволяет разделить JavaScript вашего приложения на несколько фрагментов, связанных с разными маршрутами или функциями. Этот подход отправляет пользователям только тот JavaScript, который им нужен, во время начальной загрузки приложения, сокращая время загрузки.

Методы разделения кода

Разделение кода может осуществляться на двух уровнях: уровне компонента и уровне маршрута .

  • При разделении кода на уровне компонентов вы перемещаете компоненты в отдельные фрагменты JavaScript и лениво загружаете их, когда они необходимы.
  • При разделении кода на уровне маршрута вы инкапсулируете функциональность каждого маршрута в отдельный фрагмент. Когда пользователи перемещаются по вашему приложению, они извлекают фрагменты, связанные с отдельными маршрутами, и получают соответствующие функции, когда они в этом нуждаются.

Этот пост посвящен настройке разделения на уровне маршрута в Angular.

Образец заявления

Прежде чем углубляться в использование разделения кода на уровне маршрута в Angular, давайте посмотрим на пример приложения:

Ознакомьтесь с реализацией модулей приложения. Внутри AppModule определены два маршрута: маршрут по умолчанию, связанный с HomeComponent , и маршрут nyan , связанный с NyanComponent :

@NgModule({
  ...
  imports: [
    BrowserModule,
    RouterModule.forRoot([
      {
        path: '',
        component: HomeComponent,
        pathMatch: 'full'
      },
      {
        path: 'nyan',
        component: NyanComponent
      }
    ])
  ],
  ...
})
export class AppModule {}

Разделение кода на уровне маршрута

Чтобы настроить разделение кода, необходимо выполнить рефакторинг маршрута nyan нетерпеливого.

Версия 8.1.0 Angular CLI может сделать все за вас с помощью этой команды:

ng g module nyan --module app --route nyan

Это создаст: - Новый модуль маршрутизации под названием NyanModule . - Маршрут в AppModule под названием nyan , который будет динамически загружать NyanModule . - Маршрут по умолчанию в NyanModule . - Компонент под названием NyanComponent , который будет отображаться, когда пользователь выберет маршрут по умолчанию.

Давайте выполним эти шаги вручную, чтобы лучше понять реализацию разделения кода с помощью Angular!

Когда пользователь переходит к маршруту nyan , маршрутизатор отображает NyanComponent в выходе маршрутизатора.

Чтобы использовать разделение кода на уровне маршрута в Angular, установите свойство loadChildren объявления маршрута и объедините его с динамическим импортом:

{
  path: 'nyan',
  loadChildren: () => import('./nyan/nyan.module').then(m => m.NyanModule)
}

Есть два ключевых отличия от нетерпеливого маршрута:

  1. Вы устанавливаете loadChildren вместо component . При использовании разделения кода на уровне маршрута вам необходимо указывать на динамически загружаемые модули, а не на компоненты.
  2. В loadChildren , как только обещание разрешено, вы возвращаете NyanModule вместо указания на NyanComponent .

В приведенном выше фрагменте указано, что когда пользователь переходит к nyan , Angular должен динамически загружать nyan.module из каталога nyan и отображать компонент, связанный с маршрутом по умолчанию, объявленным в модуле.

Вы можете связать маршрут по умолчанию с компонентом, используя это объявление:

import { NgModule } from '@angular/core';
import { NyanComponent } from './nyan.component';
import { RouterModule } from '@angular/router';

@NgModule({
  declarations: [NyanComponent],
  imports: [
    RouterModule.forChild([{
      path: '',
      pathMatch: 'full',
      component: NyanComponent
    }])
  ]
})
export class NyanModule {}

Этот код отображает NyanComponent , когда пользователь переходит по адресу https://example.com/nyan .

Чтобы проверить, что маршрутизатор Angular лениво загружает nyan.module в вашей локальной среде:

  1. Нажмите «Control+Shift+J» (или «Command+Option+J» на Mac), чтобы открыть DevTools.
  2. Откройте вкладку «Сеть» .

  3. Нажмите «НЯН» в примере приложения.

  4. Обратите внимание, что файл nyan-nyan-module.js отображается на вкладке сети.

Ленивая загрузка пакетов JavaScript с разделением кода на уровне маршрута

Найдите этот пример на GitHub .

Показать счетчик

Прямо сейчас, когда пользователь нажимает кнопку NYAN , приложение не указывает, что оно загружает JavaScript в фоновом режиме. Чтобы дать пользователю обратную связь при загрузке скрипта, вам, вероятно, захочется добавить счетчик.

Для этого начните с добавления разметки для индикатора внутри элемента router-outlet в app.component.html :

<router-outlet>
  <span class="loader" *ngIf="loading"></span>
</router-outlet>

Затем добавьте класс AppComponent для обработки событий маршрутизации. Этот класс установит для флага loading значение true , когда он услышит событие RouteConfigLoadStart , и установит для флага значение false когда он услышит событие RouteConfigLoadEnd .

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  loading: boolean;
  constructor(router: Router) {
    this.loading = false;
    router.events.subscribe(
      (event: RouterEvent): void => {
        if (event instanceof NavigationStart) {
          this.loading = true;
        } else if (event instanceof NavigationEnd) {
          this.loading = false;
        }
      }
    );
  }
}

В приведенном ниже примере мы ввели искусственную задержку в 500 мс, чтобы вы могли видеть счетчик в действии.

Заключение

Вы можете уменьшить размер пакета ваших приложений Angular, применив разделение кода на уровне маршрута:

  1. Используйте генератор ленивых модулей Angular CLI для автоматического формирования динамически загружаемого маршрута.
  2. Добавьте индикатор загрузки, когда пользователь переходит по ленивому маршруту, чтобы показать, что происходит текущее действие.