Route preloading strategies in Angular

Preload routes ahead of time to speed up users' navigation.

Route-level code splitting can help you reduce the initial load time of an application by delaying the JavaScript associated with routes that aren't initially needed. This way, the Angular router waits until a user navigates to a given route before triggering a network request to download the associated JavaScript.

While this technique is great for initial page load, it can slow down navigation, depending on the users' network latency and bandwidth. One way to tackle this problem is route preloading. Using preloading, when the user is at a given route, you can download and cache JavaScript associated with routes that are likely to be needed next. The Angular router provides this functionality out of the box.

In this post, you'll learn how to speed up navigation when using route-level code splitting by taking advantage of JavaScript preloading in Angular.

Route preloading strategies in Angular

The Angular router provides a configuration property called preloadingStrategy, which defines the logic for preloading and processing lazy-loaded Angular modules. We'll cover two possible strategies:

  • PreloadAllModules, which preloads all lazy-loaded routes, as the name implies
  • QuicklinkStrategy, which preloads only the routes associated with links on the current page.

The rest of this post refers to a sample Angular app. You can find the source code on GitHub.

Using the PreloadAllModules strategy

The sample app has several lazy-loaded routes. To preload all of them using the PreloadAllModules strategy—which is built into Angular—specify it as the value for the preloadingStrategy property in the router configuration:

import { RouterModule, PreloadAllModules } from '@angular/router';
// …

RouterModule.forRoot([
  …
], {
  preloadingStrategy: PreloadAllModules
})
// …

Now serve the application and look at the Network panel in Chrome DevTools:

  1. Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.
  2. Click the Network tab.

You should see that the router downloaded nyan-nyan-module.js and about-about-module.js in the background when you opened the application:

The PreloadAllModules strategy in action.

The router also registered the modules' route declarations so that when you navigate to a URL associated with any of the preloaded modules, the transition is instantaneous.

PreloadAllModules is useful in a lot of cases. When you have dozens of modules, however, its aggressive preloading can really increase network usage. Also, since the router needs to register the routes in all the preloaded modules, it can cause intensive computations in the UI thread and lead to sluggish user experience.

The quicklink library provides a better strategy for larger apps. It uses the IntersectionObserver API to preload only modules associated with links that are currently visible on the page.

You can add quicklink to an Angular app by using the ngx-quicklink package. Start by installing the package from npm:

npm install --save ngx-quicklink

Once it's available in your project, you can use QuicklinkStrategy by specifying the router's preloadingStrategy and importing the QuicklinkModule:

import {QuicklinkStrategy, QuicklinkModule} from 'ngx-quicklink';
…

@NgModule({
  …
  imports: [
    …
    QuicklinkModule,
    RouterModule.forRoot([…], {
      preloadingStrategy: QuicklinkStrategy
    })
  ],
  …
})
export class AppModule {}

Now when you open the application again, you'll notice that the router only preloads nyan-nyan-module.js since the button in the center of the page has a router link to it. And when you open the side navigation, you'll notice that the router then preloads the "About" route:

A demo of the quicklink preloading strategy.

The above example will work for a basic application but if your application contains multiple lazy-loaded modules you will need to import the QuicklinkModule into a shared module, export it and then import the shared module into your lazy-loaded modules.

First import the QuicklinkModule from ngx-quicklink into your shared module and export it:

import { QuicklinkModule } from 'ngx-quicklink';
…

@NgModule({
  …
  imports: [
    QuicklinkModule
  ],
  exports: [
    QuicklinkModule
  ],
  …
})
export class SharedModule {}

Then import your SharedModule into all of your lazy-loaded modules:

import { SharedModule } from '@app/shared/shared.module';
…

@NgModule({
  …
  imports: [
      SharedModule
  ],
  …
});

Quicklinks will now be available in your lazy-loaded modules.

Going beyond basic preloading

While selective preloading via quicklink can significantly speed up navigation, you can make your preloading strategy even more network efficient by using predictive preloading—which is implemented by Guess.js. By analyzing a report from Google Analytics or another analytics provider, Guess.js can predict a user's navigation journey and preload only the JavaScript chunks that are likely to be needed next.

You can learn how to use Guess.js with Angular on this page from the Guess.js site.

Conclusion

To speed up navigation when using route-level code splitting:

  1. Pick the right preloading strategy depending on the size of your application:
    • Applications with few modules can use Angular's built-in PreloadAllModules strategy.
    • Applications with many modules should use a custom preloading strategy, like Angular's quicklink, or predictive preloading, as implemented in Guess.js.
  2. Configure the preloading strategy by setting the preloadStrategy property of the Angular router.