Lazy Loading Modules & Preloading Strategy in Angular 8
Tags: angular, webdev, javascript
Published: 2019-08-31 02:13:20

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](https://codinglatte.com/posts/how-to/how-to-set-up-angular-for-beginners/)

## Lazy Loading Feature Modules

To use lazy loading, first, you need to create some feature modules. Feature modules are [NgModules](https://angular.io/guide/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:

```bash
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:

```typescript
{
  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.

```bash
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

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

### Preloading All Modules

```typescript
@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:

```typescript
{
  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.

```typescript
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.

```typescript
@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.


![Lazy Loading Modules & Preloading Strategy in Angular 8](https://codinglatte.com/posts/angular/lazy-loading-modules-preloading-strategy-in-angular-8/cover.gif)

## 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](https://github.com/mgechev/ngx-quicklink).

2. Another useful library is [guess.js](https://github.com/guess-js/guess) which uses predictive ML to determine which resources to preload. You can find the Angular guide for Guess.js [here](https://guess-js.github.io/docs/angular).