How I implemented lazy loading with custom preloading strategy in Angular

Nowadays, frontend applications are fast, responsive, and user-friendly. Developers so often need to face the problem of the long initialization time of the application. In some projects, the bundle with minified code is quite big. If we combine it with a slow internet connection, the startup time of the client can be unsatisfactory. Introducing lazy loading is essential to shorten initialize time of the client. The concept is quite popular and possible to realize in the most popular frameworks.

How does it work in Angular?

Code in Angular is usually divided into the main module and feature modules. This concept helps us to separate the logic of big features. Feature modules can be imported directly into the main module. In this case, the bundle fetched on initialization will contain all the code, whether or not it is immediately necessary. We can say that the modules are eagerly loaded.

To fetch chunks of code dynamically, in smaller bundles, we should introduce lazy loading. In this approach, the bundle is split into smaller chunks, which contain modules. To make it happen, module import needs to be realized at the level of routing.

The syntax 

Starting from version 8 of Angular we can use the syntax as below. 

loadChildren: () => import('./login/login.module').then(m => m.LoginModule), 

The loadChildren argument in path declaration requires a callback, which loads our ngModule. To realize that, the import method is used. Chunks of code are assigned to different routes and are fetched on entering. This job is done only on the first visit, then cached data is used.

How to change the default preloading strategy?  

Due to the lazy loading, entering not-visited routes can be realized with some delays. Imagine the case, when we want to keep the initialization time of the application short, but also avoid waiting for another chunk of code on route change. The solution is to preload modules. In this approach, base and current route chunks are fetched at first, and immediately after them, preload is done.

To preload all the modules, PreloadAllModules class from ‘@angular/router’ can be used as part of a route’s config.

RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules }) 

How to preload only some modules?  

To preload only some of the modules, we should create a custom class, which implements PreloadingStrategy from ‘@angular/router’. Preload function receives the considered route’s data and a function dedicated to loading the assigned module. From the route object, some optional data can be read. To load the assigned chunk, we can simply use the load() function.

export class AppCustomPreloader implements PreloadingStrategy { 

  preload(routeRouteload: () => Observable<any>): Observable<any> { 

    return route.data?.preload ? load() : of(null); 

  } 

} 

To decide if the module should be preloaded, we can add data to a path declaration. 

  { 

    path: 'login', 

    loadChildren: () => import('./login/login.module').then(m => m.LoginModule), 

    data: { preload: true } 

  }, 

What is more, a declaration of preloading strategy is needed. 

RouterModule.forRoot(routes, { preloadingStrategy: AppCustomPreloader }) 

We also need to provide a custom preloader. Finally, the routing module can look as below. 

export const routesRoutes = [ 

  { 

    path: 'home', 

    loadChildren: () => import('./home/home.module').then(m => m.HomeModule), 

    canActivate: [AuthGuard], 

  }, 

  { 

    path: 'login', 

    loadChildren: () => import('./login/login.module').then(m => m.LoginModule), 

    data: { preload: true } 

  }, 

  { path: '**'redirectTo: 'home' } 

]; 

 
 

@NgModule({ 

  declarations: [], 

  imports: [ 

    CommonModule, 

    RouterModule.forRoot(routes, { preloadingStrategy: AppCustomPreloader }) 

  ], 

  exports: [ 

    RouterModule 

  ], 

  providers: [AppCustomPreloader] 

}) 

export class AppRoutingModule { } 

Summary 

Modifying modules’ loading strategy is quite easy in Angular. To make the app fast, chunks of code should be as small as possible. In more complex cases, lazy loading can cause content shifting. There are plenty of other techniques to avoid that. However, the main issue of lazy loading can be overcome by customizing the default preloading strategy. It is worth considering at the beginning of the application’s life. Despite this, switching from eagerly loading to lazy loading shouldn’t be a big problem.

Tags: , , ,