
Одна из проблем с созданием одностраничного приложения (SPA) заключается в том, что вы можете загрузить все приложение, когда пользователь впервые запускает приложение, но большая его часть никогда не используется. Конечно, навигация приятная и быстрая после первоначальной загрузки, но это замедляет начальную загрузку по мере ее увеличения. И это может быть оправдано, если пользователь переходит ко всем или большинству загруженных маршрутов. Но когда большинство маршрутов никогда не активируются, это просто большая потеря. К счастью, с Angular это достаточно легко исправить с помощью ленивой загрузки. И ленивую загрузку очень легко настроить в Angular.
Кстати: этот пост в блоге посвящен Angular 2, но, поскольку мы больше не должны использовать 2, это просто Angular :-)
Активная загрузка маршрутов
Ниже пример энергичной загрузки с маршрутами Angular. Обратите внимание, что HTTP-трафик вообще отсутствует, когда я нажимаю на разные ссылки и активируются разные маршруты. Конечно, это очень простой пример, и в реальном приложении вы, скорее всего, будете извлекать некоторые данные с помощью вызова AJAX.

Итак, какой код я здесь использовал?
Большая его часть была сгенерирована с помощью Angular CLI. Вы можете увидеть весь код здесь, но он сводится к основному AppModule с двумя подмодулями: Mod1Module и Mod2Module, оба сгенерированы с помощью CLI, и к каждому добавлен один маршрут и компонент. Mod1Module посвящен книгам, а Mod2Module — авторам. Ниже приведен пример Mod1Module.
1: import { NgModule } from '@angular/core';
2: import { CommonModule } from '@angular/common';
3: import { Routes, RouterModule } from '@angular/router';
4:
5: import { BooksComponent } from './books/books.component';
6:
7: const routes: Routes = [
8: { path: 'books', component: BooksComponent },
9: ];
10:
11: @NgModule({
12: imports: [
13: CommonModule,
14: RouterModule.forChild(routes)
15: ],
16: declarations: [BooksComponent],
17: })
18: export class Mod1Module { }
AppModule также довольно прост. Он добавляет два подмодуля и инициализирует модуль маршрутизации. Поскольку оба используемых маршрута определены в подмодулях, таблица маршрутизации здесь фактически пуста.
1: import { BrowserModule } from '@angular/platform-browser';
2: import { NgModule } from '@angular/core';
3: import { FormsModule } from '@angular/forms';
4: import { HttpModule } from '@angular/http';
5: import { Routes, RouterModule } from '@angular/router';
6:
7: import { AppComponent } from './app.component';
8:
9: import { Mod1Module } from './mod1/mod1.module';
10: import { Mod2Module } from './mod2/mod2.module';
11:
12: const routes: Routes = [];
13: const routerModule = RouterModule.forRoot(routes);
14:
15: @NgModule({
16: declarations: [
17: AppComponent
18: ],
19: imports: [
20: BrowserModule,
21: FormsModule,
22: HttpModule,
23: routerModule,
24: Mod1Module,
25: Mod2Module
26: ],
27: providers: [],
28: bootstrap: [AppComponent]
29: })
30: export class AppModule { }
Представление для основного AppComponent также довольно простое. Есть две ссылки с тегами привязки, использующие директиву RouterLink, чтобы пользователь мог перемещаться. Наконец, есть директива RouterOutlet для отображения шаблона компонентов маршрута.
1: <h1>
2: {{title}}
3: </h1>
4:
5: <nav>
6: <a routerLink="/books">Books</a>
7: <a routerLink="/authors">Authors</a>
8: </nav>
9:
10: <hr />
11:
12: <router-outlet>
13: </router-outlet>
Запуск этого с помощью ng serve работает, и, как вы можете видеть выше, приложение загружает все при запуске, никаких дополнительных запросов не выполняется, когда мы нажимаем на ссылки маршрута.
Переход на ленивую загрузку
Оказывается, переключиться на ленивую загрузку очень просто и требует лишь нескольких небольших изменений.
Мы хотим, чтобы модули суммы загружались только при необходимости, поэтому вместо этого необходимо определить основные маршруты в AppModule. И в Mod1Module, и в Mod2Module нам нужно изменить путь маршрута на пустую строку. Единственное изменение в строке 8 здесь.
1: import { NgModule } from '@angular/core';
2: import { CommonModule } from '@angular/common';
3: import { Routes, RouterModule } from '@angular/router';
4:
5: import { BooksComponent } from './books/books.component';
6:
7: const routes: Routes = [
8: { path: '', component: BooksComponent },
9: ];
10:
11: @NgModule({
12: imports: [
13: CommonModule,
14: RouterModule.forChild(routes)
15: ],
16: declarations: [BooksComponent],
17: })
18: export class Mod1Module { }
Большая часть работы должна выполняться в AppModule. Тем не менее, это всего несколько строк, и большая их часть — это удаление кода :-)
1: import { BrowserModule } from '@angular/platform-browser';
2: import { NgModule } from '@angular/core';
3: import { FormsModule } from '@angular/forms';
4: import { HttpModule } from '@angular/http';
5: import { Routes, RouterModule } from '@angular/router';
6:
7: import { AppComponent } from './app.component';
8:
9: const routes: Routes = [
10: { path: 'books', loadChildren: './mod1/mod1.module#Mod1Module' },
11: { path: 'authors', loadChildren: './mod2/mod2.module#Mod2Module' },
12: ];
13: const routerModule = RouterModule.forRoot(routes);
14:
15: @NgModule({
16: declarations: [
17: AppComponent
18: ],
19: imports: [
20: BrowserModule,
21: FormsModule,
22: HttpModule,
23: routerModule
24: ],
25: providers: [],
26: bootstrap: [AppComponent]
27: })
28: export class AppModule { }
Обратите внимание, что как TypeScript, так и импорт модулей для Mod1Module и Mod2Module исчезли. Новыми являются два маршрута, в которых определяются книги и авторы. Вместо указания загружаемого компонента имеется строка ./mod1/mod1.module#Mod1Module, указывающая на файл модуля и класс модуля для загрузки. Это в строке, потому что мы не хотим импортировать тип, они должны быть в отдельном модуле и загружаться только при необходимости. Документация здесь все еще немного скудна, так как указывает на раздел LoadChildren, который указывает на Routes :-(
Ну ладно, документация с открытым исходным кодом, так что я думаю, я должен открыть запрос на включение :-)
В любом случае, с этими небольшими изменениями и Mod1Module, и Mod2Module лениво загружаются при первой необходимости, а не при начальной загрузке страницы. Ниже вы можете увидеть, как 0.chunk.js и 1.chunk.js загружаются при первом нажатии ссылки на соответствующий модуль.

Посмотреть коммит соревнования со всеми изменениями можно здесь или репозиторий GitHub с окончательным кодом здесь.
Наслаждаться!
Первоначально опубликовано на сайте blogs.msmvps.com 2 января 2017 г.