How to lazy-load routes and import standalone components in Angular

Introduction

In Angular, routing is a key feature of application to navigate users to different pages to render components. A typical enterprise Angular application would lazy load routes and standalone components to maintain small main bund…


This content originally appeared on DEV Community and was authored by Connie Leung

Introduction

In Angular, routing is a key feature of application to navigate users to different pages to render components. A typical enterprise Angular application would lazy load routes and standalone components to maintain small main bundle to reduce the initial load time. In advanced case, such application even loads root-level and children routes to render parent and children components.

In this blog post, I would like to cover three cases of lazy loading single route and standalone component:

  • Lazy load default route
  • Lazy load routes that exist in the route array
  • Lazy load non-existing route

Define application route array

// app.route.ts

import { Route } from '@angular/router';

// lazy-load standalone component
export const APP_ROUTES: Route[] = [{
  path: 'pokemon',
  loadComponent: () => import('./pokemon/pokemon/pokemon.component')
    .then(mod => mod.PokemonComponent)
}, 
{
  path: '',
  pathMatch: 'full',
  loadComponent: () => import('./home/home.component').then(mod => mod.HomeComponent)
},
{
  path: '**',
  loadComponent: () => import('./page-not-found/page-not-found.component')
    .then(mod => mod.PageNotFoundComponent)
}];

In app.route.ts file, I defined a route array and the application should lazy load the routes when they are clicked. When the path of the route is /pokemon, Angular imports PokemonComponent. When users reach the default URL, they should see HomeComponent standalone component. For other non-existent routes, Angular imports PageNotFoundComponent that redirects to home after 10 seconds.

Set up routes in the application

// main.ts

@Component({
  selector: 'my-app',
  standalone: true,
  imports: [RouterLink, RouterOutlet],  // import RouteLink and RouterOutlet to use in inline template
  template: `
    <ul>
      <li><a routerLink="/" routerLinkActive="active">Home</a></li>
      <li><a routerLink="/pokemon" routerLinkActive="active">Show Pokemon</a></li>
      <li><a routerLink="/bad" routerLinkActive="active">Bad route</a></li>
    </ul>
    <router-outlet></router-outlet>
  `,
  styles: [`...omitted due to brevity...`]
})
export class App {}

bootstrapApplication(App, {
  providers: [
    provideHttpClient(),
    // provider to inject routes, preload all modules and trace route change events
    provideRouter(APP_ROUTES, withPreloading(PreloadAllModules), withDebugTracing())
  ]
});

In main.ts, I provided APP_ROUTES to provideRouter provider. Moreover, the provider has two features; withPreloading that preloads all modules and withDebugTracing that traces routes in debug mode.

In the inline template, each hyperlink has routeLink directive that specifies the path and <router-outlet> is the placeholder of the standalone component. Finally, the page renders three routes for clicking.

Home Page

Lazy load default route

When browser first loads the application or user clicks 'Home', routeLink equals to '/' and it meets path: '' condition. Therefore, HomeComponent is imported

{
  path: '',
  pathMatch: 'full',
  loadComponent: () => import('./home/home.component').then(mod => mod.HomeComponent)
}
// home.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-home',
  standalone: true,
    template: `
    <div>
      <h2>Click Pokemon Link</h2>
    </div>
  `,
  styles: [`
    :host {
      display: block;
    }
  `]
})
export class HomeComponent {}

The simple component displays "Click Pokemon Link" header and serves its only purpose.

Lazy load routes that exist

When user clicks "Show Pokemon", routeLink changes to "/pokemon" and it matches the route path of "pokemon".

{
  path: 'pokemon',
  loadComponent: () => import('./pokemon/pokemon/pokemon.component')
    .then(mod => mod.PokemonComponent)
}

The route eventually imports Pokemon component that also renders the rest of the child components.

// pokemon.component.ts

@Component({
  selector: 'app-pokemon',
  standalone: true,
  imports: [AsyncPipe, NgIf, PokemonControlsComponent, PokemonPersonalComponent, PokemonTabComponent],
  template: `
    ...render HTML and child components...  
  `,
  styles: [`...omitted due to brevity...`],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PokemonComponent {
  retrievePokemon = retrievePokemonFn();
  pokemon$ = getPokemonId().pipe(switchMap((id) => this.retrievePokemon(id)));
}

We hit a bad route, how do we fix it?

In the last scenario, user clicks "Bad route" but "/bad" does not exist in the routes array. Will the application break? Fortunately, I can define path: "**" route that catches all unmatched paths.

{
  path: '**',
  loadComponent: () => import('./page-not-found/page-not-found.component')
    .then(mod => mod.PageNotFoundComponent)
}

This route renders PageNotFoundComponent and informs users that the page does not exist.

// page-not-found.component.ts

@Component({
  selector: 'app-page-not-found',
  standalone: true,
  imports: [AsyncPipe],
  template: `
    <div>
      <h2>Page not found</h2>
      <p>Return home after {{ countDown$ | async }} seconds</p>
    </div>
  `,
  styles: [`...omitted due to brevity...`]
})
export class PageNotFoundComponent implements OnInit {
  countDown$ = timer(0, 1000)
    .pipe(
      map((value) => 10 - value),
      takeWhile((value) => value >= 0),
      shareReplay(1),
    );

  redirectHome$ = this.countDown$.pipe(
      tap((value) => {
        if (value <= 0) {
          inject(Router).navigate(['']);
        }
      }),
      takeUntilDestroyed()
    );

  ngOnInit(): void {
    this.redirectHome$.subscribe();
  }
}

This component displays "Page not found" message and redirects home after 10 seconds.

The following Stackblitz repo shows the final results:

This is the end of the blog post and I hope you like the content and continue to follow my learning experience in Angular and other technologies.

Resources:


This content originally appeared on DEV Community and was authored by Connie Leung


Print Share Comment Cite Upload Translate Updates
APA

Connie Leung | Sciencx (2023-05-14T11:00:09+00:00) How to lazy-load routes and import standalone components in Angular. Retrieved from https://www.scien.cx/2023/05/14/how-to-lazy-load-routes-and-import-standalone-components-in-angular/

MLA
" » How to lazy-load routes and import standalone components in Angular." Connie Leung | Sciencx - Sunday May 14, 2023, https://www.scien.cx/2023/05/14/how-to-lazy-load-routes-and-import-standalone-components-in-angular/
HARVARD
Connie Leung | Sciencx Sunday May 14, 2023 » How to lazy-load routes and import standalone components in Angular., viewed ,<https://www.scien.cx/2023/05/14/how-to-lazy-load-routes-and-import-standalone-components-in-angular/>
VANCOUVER
Connie Leung | Sciencx - » How to lazy-load routes and import standalone components in Angular. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2023/05/14/how-to-lazy-load-routes-and-import-standalone-components-in-angular/
CHICAGO
" » How to lazy-load routes and import standalone components in Angular." Connie Leung | Sciencx - Accessed . https://www.scien.cx/2023/05/14/how-to-lazy-load-routes-and-import-standalone-components-in-angular/
IEEE
" » How to lazy-load routes and import standalone components in Angular." Connie Leung | Sciencx [Online]. Available: https://www.scien.cx/2023/05/14/how-to-lazy-load-routes-and-import-standalone-components-in-angular/. [Accessed: ]
rf:citation
» How to lazy-load routes and import standalone components in Angular | Connie Leung | Sciencx | https://www.scien.cx/2023/05/14/how-to-lazy-load-routes-and-import-standalone-components-in-angular/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.