Создание своей стратегии загрузки в Angular
Недавно наткнулся на собеседовании наткнулся на вопрос, как создать свою стратегию загрузки. В интернете много примеров о том, как это делается для NgModule приложений, но для standalone примеров совсем немного. Что-ж, разберем этот вопрос детальнее.
В Angular есть несколько стратегий загрузки модулей и компонентов, которые позволяют оптимизировать работу приложения, особенно в больших проектах. Всего разработчику доступно 3 стратегии:
- NoPreloading. Отключает предзагрузку. Ленивая загрузка будет происходить только в момент перехода на соответствующий маршрут.
- PreloadingAllModules. Предзагружает все ленивые модули и компоненты, как только основное приложение будет загружено. Загрузка происходит в фоновом режиме, не блокируя основную инициализацию.
- RouterPreloader. Это механизм для создания кастомной стратегии предзагрузки, позволяющий вам определять, какие модули или компоненты должны быть предзагружены
Именно третья стратегия позволяет создать новую, для этого нужно класс реализующий интерфейс PreloadingStrategy:
import { PreloadingStrategy, Route } from '@angular/router'; import { Observable, of } from 'rxjs'; export class CustomPreloadingStrategy implements PreloadingStrategy { preload(route: Route, load: () => Observable<any>): Observable<any> { // Предзагружаем только те модули, где указан параметр data.preload === true return route.data?.['preload'] ? load() : of(null); } }
и сообщить приложению об имеющейся стратегии на момент загрузки приложения (main.ts) и зарегистрировать DI токен (можно так же через providedIn: 'root'):
import { provideRouter, withPreloading, RouterPreloader } from '@angular/router'; bootstrapApplication(AppComponent, { providers: [ { provide: RouterPreloader, useClass: CustomPreloadingStrategy }, // регистрируем токен provideRouter(routes, withPreloading(CustomPreloadingStrategy)) // передаём в роутер стратегию ], });
Остаётся прописать флаг в роутингах, чтобы Angular знал что стоит предзагружать - а что нет.
const routes: Routes = [ { path: 'important', loadChildren: () => import('./important/important.module').then(m => m.ImportantModule), data: { preload: true }, // Будет предзагружен }, { path: 'optional', loadChildren: () => import('./optional/optional.module').then(m => m.OptionalModule), data: { preload: false }, // Не будет предзагружен }, ];