Optimising Angular Performance with Lazy loading and Quicklink


Performance is one of the most important things on any app.

Mostly when working on large projects, we will have multiple routes, complex business rules and a lot of code for sure.

By default, Angular compiles all our code in a single file called main.js. In small projects this is probably fine, but we usually work on enterprise applications so instead of having a single file, we can create one js for each feature module and download it when the route is invoked.

Let’s see the difference between default loading and lazy loading feature modules

Alt Text

Angular provides lazy-loading to help us to achieve this goal. In this post we will

  • Implement lazy-loading feature modules
  • Implement ngx-quicklink: router preloading strategy which automatically downloads the lazy-loaded modules associated with all the visible links on the screen (any routerLink found will be downloaded). This is not part of Angular, it’s a library written by Minko Gechev.

Let’s get started with our example, a simple app with 2 feature modules

  • list of dogs
  • list of cats
 ng new lazy-loading-quicklink

Now, we are going to create the first feature module with lazy loading

ng generate module dogs --route dogs --module app.module

as result we have

  • created new dogs.module.ts
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { DogsRoutingModule } from './dogs-routing.module';
import { DogsComponent } from './dogs.component';

@NgModule({
  declarations: [DogsComponent],
  imports: [CommonModule, DogsRoutingModule],
})
export class DogsModule {}

  • created new dogs-routing.module.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { DogsComponent } from './dogs.component';

const routes: Routes = [{ path: '', component: DogsComponent }];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule],
})
export class DogsRoutingModule {}

  • updated app-routing.module.ts including new dogs routing (note that lazy loading is in place)
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  {
    path: 'dogs',
    loadChildren: () => import('./dogs/dogs.module').then((m) => m.DogsModule),
  }
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes),
  ],
  exports: [RouterModule],
})
export class AppRoutingModule {}

  • created new dogs.component

Another important step is to include router-outlet in the app.component.html to be able to perform routing actions


<div>
  <a routerLink="">home</a>
</div>
<div>
  <a routerLink="dogs">dogs</a>
</div>
<router-outlet></router-outlet>

So, we have our feature module, let’s now implement ngx-quicklink

  • npm i ngx-quicklink --save

Once it’s done, we need to update app.module.ts to import QuicklinkModule


import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { QuicklinkModule } from 'ngx-quicklink';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, AppRoutingModule, QuicklinkModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

Next step is to set the preloadingStrategy on app-routing.module.ts


import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { QuicklinkStrategy } from 'ngx-quicklink';

const routes: Routes = [
  {
    path: 'dogs',
    loadChildren: () => import('./dogs/dogs.module').then((m) => m.DogsModule),
  },
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes, { preloadingStrategy: QuicklinkStrategy }),
  ],
  exports: [RouterModule],
})
export class AppRoutingModule {}

We have defined preloadingStrategy in our routing module, it means when routerLink=“dogs” is rendered, dogs module will be downloaded before hand.

Here we have some screenshots to show what is going on

routerLink is rendered Alt Text

dogs feature module is downloaded Alt Text

Alt Text

In case you don’t want to prefetch a route, you can set preload:false


const routes: Routes = [
  {
    path: 'dogs',
    loadChildren: () => import('./dogs/dogs.module').then((m) => m.DogsModule),
    data: {
      preload: false,
    },
  },
]; 

In that case, feature module will be downloaded once you access to the route and not before.

Conclusion Lazy loading is a great technique to enhance performance splitting the code. If we want to go one step forward, ngx-quicklink helps us to improve even more adding prefetching feature modules. It’s not hard to implement and performance result are much better.

Thanks for reading

References