Users want fast apps. Getting your JavaScript bundles to your browser as quickly as possible and before your user needs them can make a huge and positive impact on their user experience. Knowing how you can improve that experience is important.

One way you can improve user experience with your Angular apps is to strategically decide which bundles to preload. You control when your bundles load and which bundles load. This is why you should explore choosing a built-in or creating your own custom Angular preload strategy.

In this series we'll explore a few of your options for preloading Angular bundles.

Here are the other articles in this series

Opting in

The "opt in" strategy is like a buffet. You pick what you want to preload, and leave the rest to load as needed.

Creating custom preload strategies is a great way to control the manner in which the bundles preload. The custom OptInPreloadStrategy preload strategy let's you indicate which lazy loaded bundles should be preloaded.

You can do this by creating a new class that implements that PreloadingStrategy interface, and providing it in the root. Then you must implement the preload function and return the load() function when you want to tell Angular to preload the function.

Notice the preload function in the class OptInPreloadStrategy checks the route definition for a data property that contains a preload property. If that data.preload property exists and is a truthy value, then the load() function will be returned. When the load() function is returned, the router listens to this Observable and will make the network call to load the route's bundle.

import { Injectable } from '@angular/core';
import { PreloadingStrategy, Route } from '@angular/router';
import { Observable, EMPTY } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class OptInPreloadStrategy implements PreloadingStrategy {
  preload(route: Route, load: () => Observable<any>): Observable<any> {
    return route.data && route.data['preload'] ? load() : EMPTY;
  }
}

Route Definitions

This strategy requires that you indicate which routes should be preloaded. You can do this by adding the data.preload property and set it to true in your route definition, as shown below.

export const routes: Routes = [
  { path: '', pathMatch: 'full', redirectTo: 'heroes' },
  {
    path: 'dashboard',
    loadChildren: () =>
      import('app/dashboard/dashboard.module').then(m => m.DashboardModule),
    data: { preload: true }
  },
  {
    path: 'heroes',
    loadChildren: () =>
      import('app/heroes/heroes.module').then(m => m.HeroesModule),
    data: { preload: true }
  },
  {
    path: 'villains',
    loadChildren: () =>
      import('app/villains/villains.module').then(m => m.VillainsModule)
  },
  { path: '**', pathMatch: 'full', component: PageNotFoundComponent }
];

Notice that the dashboard and heroes routes both have the preload.data property set to true. However, the villains route does not have this property set. In this scenario the heroes and dashboard would preload, but the villains would only load when the user navigates to this route.

Setting the Custom OptInPreloadStrategy

Then when setting up your RouterModule, pass the router options including the preloadingStrategy to the forRoot() function.

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

Try It

After applying this strategy and setting some of the route definition's routes data.preload = true, rebuild and run your app with ng serve. Open your browser, open your developer tools, and go to http://localhost:4200. When you inspect the Network tab in your browser you will see all of your bundles already preloaded.

Notice that the dashboard and heroes are already preloaded, but villains are not. If you wish to really see this make a difference, enable throttling in your developer tools to a slower connection such as 3G, then refresh the page. The preloading will be much more visible now in the Network tab.

Deciding What Is Right For Your App

Now that you know how to create your own preload strategy such as OptInPreloadStrategy, how do you evaluate if this is the right strategy for your app?

It might make sense to consider which bundles would help improve your users' experience by being preloaded first. You could talk to your business users (the stakeholders in your app) and discover what they feel are the most frequented areas of your app. You could use analytics from existing apps or perform user studies to determine this, as well.

In the end the decision is up to you. I recommend before choosing this options, or any preload strategy, that you test at various network speeds under various valid and common user workflows. This data will help you decide if this is the right strategy for you, or if another may be more beneficial for users of your app.

Resources