In this lesson, we are going to cover:

  • Lazy Loading of Feature Modules
  • And Creating Preloading Strategy for Lazy-Loaded Modules

Prerequisite

  1. Install Angular CLI and Create a new Angular Application

Lazy Loading Feature Modules

To use lazy loading, first, you need to create some feature modules. Feature modules are NgModules created for the purpose of code organization. Feature modules allow you to separate code for a feature/functionality from the rest of your app. Components, Pipes, Directives, etc. inside a feature module are isolated from the rest of your app and are only accessible inside the feature module.

To create feature modules, we have two option – a manual approach and automated approach.

Manual Approach

In this approach, we are going to do everything ourselves. First, we are going to use Angular CLI command ng generate module to generate a feature module. Please note, for the purpose of lazy loading, our module needs to have routing enabled. We can do this by using the --routing flag, as shown below:

ng generate module lazyloadedmodule1 --routing

The above command is going to create a Lazymodule1Module and Lazymodule1RoutingModule. Where the first is the NgModule and the second is the routing module where routes for our feature module will live.

Secondly, we will need some components or directives or pipes, etc. for our feature module. The simplest approach is to put components/directives/pipes inside the same directory as our feature module or its sub-directories. This way, they will be registered under our feature module. You can also use the --module flag if you want your feature module and its related assets to live in separate directories.

And finally, we need to add the feature module inside our app router module, as shown below:

{
  path: 'lazy-module-1',
  loadChildren: () =>
    import('./lazymodule1/lazymodule1.module').then(m => m.Lazymodule1Module)
}

Automated Approach

As of Angular 8, you can generate a feature module with routing enabled, a default component and add as a lazy loaded route to the router.

ng generate module lazymodulename --module app --route lazy-module-route

The above command must have the following flags:

  • --module flag (Required) – The module where to register the route for the app.

  • --route flag (Required) - The path for your lazy module route.

If any of the above flags are missing, it will fail.

NB: You can use the canLoad guard to prevent feature module from loading if the user is not authorized to access a route. You can use canLoad guard alongside canActivate and canActivateChild guards which prevent unauthorized requests.

Preloading Strategy for Lazy-Loaded Modules

A preload strategy creates rules that determine which modules to preload. So, if you have multiple lazy-loaded modules, a preloading strategy would determine which modules to preload and when to preload them.

Angular supplies two preloading strategies out of the box:

  • NoPreloading - No preloading (default)

  • PreloadAllModules - Preload of all lazy-loaded modules.

No Preloading – Default preloading strategy

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

Preloading All Modules

@NgModule({
  imports: [
    RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules })
  ],
  exports: [RouterModule]
})

Creating a Custom Preload Strategy

The first thing we need to do is to determine the formula/strategy to use to determine which lazy-loaded modules to preload. For instance, we can add a preload flag to the routes you want to preload and then check for the flag when determining whether to preload the lazy-loaded module:

{
  path: 'module-8',
  loadChildren: () => import('./lazymodule8/lazymodule8.module').then(m => m.Lazymodule8Module),
  data: { preload: true } // preload flag
}

And then we are going to create a service that implements PreloadingStrategy interface. To implement the interface, we are going to add a preload function. The preload function accepts two arguments – a route and a loader function:

  • The route is the route to consider for preloading.

  • And the loader function loads the lazy-loaded module asynchronously when called.

Inside the preload function, we are going to check If the preload flag is set to true, and then return the loader function else we return a null observable.

export class MyPreloadingStrategyService implements PreloadingStrategy {

  preload(route: Route, load: () => Observable<any>): Observable<any> {
    if (route.data && route.data['preload']) {
      return load();
    } else {
      return of(null);
    }
  }

}

And finally, we need to set the preload service we created above as the preloading strategy.

@NgModule({
  imports: [
    RouterModule.forRoot(routes, {
      preloadingStrategy: MyPreloadingStrategyService // our preloading service here
    })
  ],
  exports: [RouterModule]
})

export class AppRoutingModule {}

Preload Strategy Demo

The following demo uses the preload strategy above. It has 8 routes, where only even-numbered routes are preloaded. After initially loading the application, the app is taken to offline mode and you will notice only preloaded routes load while the others fail due to lack of network.

TIPS

  1. You can use ngx-quiklink library to preload all lazy-loaded modules associated with visible links on the screen. You can learn more here.

  2. Another useful library is guess.js which uses predictive ML to determine which resources to preload. You can find the Angular guide for Guess.js here.