Angular Preload Lazy Modules with Delay

The good news, Angular has really good support for lazy loading with 2 preloading strategies by default.

import { NgModule } from '@angular/core';
import { PreloadAllModules, Routes, RouterModule } from '@angular/router';
import { Feature1Component } from './feature-1/feature-1.component';

const routes: Routes = [
  {
    path: '',
    redirectTo: 'feature-1',
    pathMatch: 'full'
  },
  {
    path: 'feature-1',
    component: Feature1Component
  },
  {
    path: 'feature-2',
    loadChildren: './feature-2/feature-2.module#Feature2Module',
  }
];

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

Default basic angular lazy loading greatly increases the initial load time of the application. With PreloadAllModules loads all modules in the background. While the lazy loading style keeps the core starter pack small at first load and it also loads all of the lazy modules in the background. This means that the module is already loaded into memory when the user clicks the link. This mechanism allows Angular to start building immediately, instead of waiting for the module to be downloaded over the network.

For some application, especially the ones with meaningful API calls at the beginning, this can be a problem. While the first loaded module trying to reach the API for crucial information, Angular tries to download the other modules and fills the network bandwidth.

If your app is large and complicated enough, loading the entire thing might not be the best option. You might waste user’s bandwidth by downloading screens they might not visit. Your initial load might also be even slower using PreloadAllModules if it takes considerable time to parse and compile the JavaScript. Fortunately, we can also define custom pre-loading strategies in Angular. 

To create this strategy, Angular provides an abstract class called PreloadingStrategy that you can implement. This class has one method you need to override, preload, which takes in the configured lazy route, and a parameterless function you can call to programmatically load the lazy route. It returns an observable of type any. A better strategy can be created by utilizing this class.

export class DelayedPreloadingStrategy implements PreloadingStrategy {
  public preload(route: Route, fn: () => Observable<boolean>): Observable<boolean> {
    return observableOf(true).pipe(delay(15000), mergeMap((_: boolean) => fn()));
  }
}

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

DelayedPreloadingStrategy does exactly what PreloadAllModules does but after 15 seconds of app provocation. This gives the app enough time to process initial code and make necessary API calls.