Angular автомонмный маршрутизатор API
Зададим себе вопрос сколько мы можем вытрясти из связки Routers?
А давайте попробуем и рассмотрим все на примере. Начнем кодировать простое приложение с двумя лениво загружаемыми маршрутами (/movies
и /shows
), которое нам позволяет составить список фильмов и телепередач.
Вы можете создавать функциональные модули с отложенной загрузкой с помощью простой единственной команды.
Итак, у нас есть приложение с двумя хорошими маршрутами. У каждого маршрута есть служба, которая доставляет товары и некоторые компоненты для их отображения.
Давайте сосредоточимся на самой интересной части, которая для этой статьи является размером пакета.
Все приложение занимает 246,23 КБ, из них 203,17 КБ - оснговной пакет и 65,62 КБ - маршрутизатор. В настоящее время это составляет 26,6% от нашего текущего приложения. 26,6% может показаться много, но это потому, что наше приложение очень тривиально и, следовательно, очень маленькое.
Давайте реорганизуем наше приложение, чтобы использовать автономные API маршрутизатора.
Автономные API-интерфейсы
Перед использованием автономного API мы должны ознакомиться с официальными документами, чтобы понять, как полностью использовать автономные API-маршрутизаторы.
Angular теперь предоставляет функцию provideRouter
. Эта функция позволяет нам предоставить нашему приложению необходимую функциональность маршрутизатора (маршруты и функции маршрутизатора). Сегодня эти функции маршрутизатора предоставляются RouterModule
.
Итак, у нас есть возможность обеспечить функциональность маршрутизатора, но как насчет компонентов и директив, таких как router-outlet
или routerLink
? Как мы их получим? Это довольно просто: мы можем импортировать их. Все компоненты и директивы маршрутизатора теперь доступны как автономные API.
Похоже, что новые API предоставляют все, что нам нужно. Как мы должны использовать функцию provide Router?
Мы можем передать функцию provideRouter
в качестве параметра функции bootstrapApplication
.
const appRoutes: Routes = [];
bootstrapApplication(AppComponent,
{
providers: [
provideRouter(appRoutes,
withDebugTracing(),
withRouterConfig({paramsInheritanceStrategy: 'always'}))
]
}
);
Что такое bootstrap Application
? В моем приложении мы используем функцию bootstrapModule
, предоставляемую функцией platformBrowserDynamic
.
bootstrapApplication
была введена в версии 14 и позволяет нам загружать автономный компонент.
Означает ли это, что мне нужно изменить свое приложение на автономные компоненты, чтобы воспользоваться функцией provideRouter
?
Да, по крайней мере для компонентов приложения. Давайте протестируем два разных подхода.
В первом подходе мы преобразуем наш AppComoponent
в автономный компонент, но мы по прежнему будем использовать RouterModule
в наших функциях с отложенной загрузкой. Во втором подходе мы преобразуем все приложения в автономные компоненты.
Гибридный подход
Чтобы воспользоваться преимуществами функции provideRouter
, мы должны преобразовать наш AppComponent
в автономный компонент, добавив автономное свойство со значением true
.
Поскольку в нашем шаблоне используются router-outlet
и routerLink
, нам дополнительно необходимо импортировать автономные API-интерфейсы RouterOutlet
и RouterLinkWithHref
.
import { Component } from '@angular/core';
import {RouterLinkWithHref, RouterOutlet} from "@angular/router";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
imports: [
RouterOutlet,
RouterLinkWithHref
],
standalone: true
})
export class AppComponent {
}
Как только мы преобразовали наш AppComponent
в автономный компонент, мы можем удалить app.module.ts
и app.routing.module.ts
. На данный момент остался только один шаг - настроить файл main.ts
.
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
import {bootstrapApplication} from "@angular/platform-browser";
import {AppComponent} from "./app/app.component";
import {provideRouter, Routes} from "@angular/router";
const routes: Routes = [
{ path: 'shows', loadChildren: () => import('./app/features/shows/shows.module').then(m => m.ShowsModule) },
{ path: 'movies', loadChildren: () => import('./app/features/movies/movies.module').then(m => m.MoviesModule) }
];
if (environment.production) {
enableProdMode();
}
bootstrapApplication(AppComponent, {
providers: provideRouter(routes)
})
Мы переместили маршруты из app.routing.module.ts
в наш main.ts
и скорректировали пути. Затем мы передаем его функции provideRouter
в опциях провайдеров функции bootstrapApplication
.
Мы успешно использовали некоторые из автономных API маршрутизаторов. Давайте рассмотрим размер пакета нашего приложения.
Общий размер приложения уменьшился до 243,08 КБ. Интересная часть заключается в том, что даже общий размер приложения уменьшился, сам маршрутизатор увеличился на 0,13 КБ.
Это потому, что мы теперь используем функцию provideRouter
в сочетании RouterModule
, который мы еще используем в модулях функций с отложенной загрузкой.
Этот подход не приводит к желаемому уменьшению размера пакета маршрутизатора.Но это все равно хороший подход, поскольку его можно использовать в качестве частичного шага миграции к полностью автономным компонентам.
Полноценные автономные компоненты
Давайте преобразуем наши модули маршрутизации с отложенной загрузкой в автономные компоненты с отложенной загрузкой.
Для этого мы сначала удалим файлы movies.routing.module.ts
и movies.module.ts
. Далее мы должны преобразовать movies.component.ts
в отдельный компонент.
import {Component} from '@angular/core';
import {NgFor} from "@angular/common";
import {MoviesService} from "./movies.service";
import {MovieCardComponent} from "./movie-card/movie-card.component";
@Component({
selector: 'app-movies',
templateUrl: './movies.component.html',
styleUrls: ['./movies.component.scss'],
standalone: true,
imports: [MovieCardComponent, NgFor]
})
export class MoviesComponent {
movies = this.moviesService.getMovies();
constructor(private moviesService: MoviesService) { }
}
Мы устанавливаем для параметра standalone
в декораторе компонентов значение true
и добавляем массив imports
, содержащий значения MovieCardComponent
и NgFor
.
Уже преобразовал компонент видеокарты в отдельный компонент.
Те же шаги должны быть выполнены для маршрута shows
. Я полагаю, вы не хотели бы, чтобы снова перечислял из здесь.
После того, как мы преобразовали наши функции в автономные компоненты, нам нужно пересмотреть и реорганизовать маршруты в main.ts
, чтобы использовать метод loadComponent
вместо loadChildren
.
const routes: Routes = [{ path: 'shows', loadComponent: () => import('./app/features/shows/shows.component').then(c => c.ShowsComponent) }, { path: 'movies', loadComponent: () => import('./app/features/movies/movies.component').then(c => c.MoviesComponent) }];
if (environment.production) {
enableProdMode();
}
bootstrapApplication(AppComponent, {
providers: [provideRouter(routes)]
})
Как следует из названия loadComponent
позволяет нам лениво загружать компонент (автономно) без использования модуля.
Мы успешно преобразовали наше приложение в автономные компоненты. Кроме того, наше приложение больше не использует RouterModule
, вместо этого оно теперь использует только автономные API маршрутизаторов.
Давайте снова создадим наше приложение и проверим полученный пакет.
Общий размер пакета теперь составляет 233,61 КБ. Это общее уменьшение на 12,62 КБ для того же набора функций. Но нас особенно интересует маршрутизатор,
Размер маршрутизатора теперь составляет 60,54 КБ. Это уменьшение на 5,08 КБ. Это 7,74%. 7,74% соответствуют моему упрощенному варианту использования с использованием source-map-explorer
в качестве инструмента измерения. Очень хорошо могу представить, что в более сложных сценариях или, возможно, с другим инструментом измерения вы можете получить до 11%.
Вывод
Новые автономные API-интерфейсы маршрутизаторов просто фантастичны. Они позволяют нам реализовать те же потрясающие функции, что и в случае с пакетами меньшего размера.
Имейте в виду, что в настоящее время они находятся в предварительном просмотре для разработчиков и будут стабильны в версии 15. Поэтому я не стал бы их использовать сегодня для продуктивного кода. Кроме того, они вынуждают вас использовать автономные компоненты во всем нашем приложении.
В зависимости от размера вашего приложения частичная миграция может быть хорошим способом перевести ваше приложение на автономные API-интерфейсы маршрутизатора. Однако имейте ввиду, что смешивание provideRouter с RouterModule должно быть только промежуточным шагом, а не конечным решением.