typescript 48 lines · 7 steps

A custom preloading strategy in Angular

Control which lazy-loaded route modules preload — and when — using route data flags and a delay.

Explained by highlit
1import { Injectable } from '@angular/core';
2import { PreloadingStrategy, Route, Routes, RouterModule } from '@angular/router';
3import { NgModule } from '@angular/core';
4import { Observable, of, timer } from 'rxjs';
5import { mergeMap } from 'rxjs/operators';
6 
7@Injectable({ providedIn: 'root' })
8export class SelectivePreloadStrategy implements PreloadingStrategy {
9 preload(route: Route, load: () => Observable<unknown>): Observable<unknown> {
10 if (!route.data?.['preload']) {
11 return of(null);
12 }
13 
14 const delay = (route.data['preloadDelay'] as number) ?? 0;
15 return timer(delay).pipe(mergeMap(() => load()));
16 }
17}
18 
19const routes: Routes = [
20 {
21 path: 'dashboard',
22 loadChildren: () =>
23 import('./dashboard/dashboard.module').then((m) => m.DashboardModule),
24 data: { preload: true },
25 },
26 {
27 path: 'reports',
28 loadChildren: () =>
29 import('./reports/reports.module').then((m) => m.ReportsModule),
30 data: { preload: true, preloadDelay: 3000 },
31 },
32 {
33 path: 'admin',
34 loadChildren: () =>
35 import('./admin/admin.module').then((m) => m.AdminModule),
36 data: { preload: false },
37 },
38];
39 
40@NgModule({
41 imports: [
42 RouterModule.forRoot(routes, {
43 preloadingStrategy: SelectivePreloadStrategy,
44 }),
45 ],
46 exports: [RouterModule],
47})
48export class AppRoutingModule {}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1A PreloadingStrategy lets you decide per-route whether a lazy module downloads in the background after the app boots.
  2. 2Route data is a flexible channel for passing configuration into infrastructure like preloaders.
  3. 3Returning of(null) from preload cleanly opts a route out without loading its bundle.

Related explainers

python
from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel, ConfigDict, EmailStr
from sqlalchemy.orm import Session

Building a users router in FastAPI

routing serialization dependency-injection
Intermediate 7 steps
typescript
type Event = Record<string, unknown>;
 
interface BatcherOptions {
  endpoint: string;

Batching analytics events in TypeScript

batching buffering async
Intermediate 8 steps
typescript
import { Processor, WorkerHost, OnWorkerEvent } from '@nestjs/bullmq';
import { Logger } from '@nestjs/common';
import { Job } from 'bullmq';
import { MailerService } from '../mailer/mailer.service';

Processing background email jobs in NestJS

job-queue background-processing dependency-injection
Intermediate 7 steps
typescript
import { Component, computed, inject, signal } from '@angular/core';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { CommonModule } from '@angular/common';
 

Building a signup stepper in Angular

signals reactive-forms form-validation
Intermediate 10 steps
typescript
type Change =
  | { kind: "added"; path: string; value: unknown }
  | { kind: "removed"; path: string; value: unknown }
  | { kind: "updated"; path: string; from: unknown; to: unknown };

Building a recursive deep-diff in TypeScript

recursion discriminated-unions type-guards
Intermediate 9 steps
typescript
import { DynamicModule, Module, Provider } from '@nestjs/common';
import Redis, { RedisOptions } from 'ioredis';
 
export const REDIS_CLIENT = Symbol('REDIS_CLIENT');

Building a dynamic Redis module in NestJS

dependency-injection dynamic-modules provider-tokens
Intermediate 8 steps

Share this explainer

Here's the card — post it anywhere.

A custom preloading strategy in Angular — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code