Faster web navigation with predictive prefetching

Learn about predictive prefetching and how Guess.js implements it.

In my Faster Web Navigation with Predictive Prefetching session at Google I/O 2019, I began by talking about optimizing web apps with code splitting and the potential performance implications for subsequent page navigation. In the second part of the talk, I discussed how to improve navigation speed by using Guess.js to set up predictive prefetching:

Code splitting for faster web apps

Web apps are slow, and JavaScript is among the most expensive resources that you ship. Waiting for a slow web app to load can frustrate your users and decrease conversions.

Slow web apps are stressful.

Lazy loading is an efficient technique to reduce the bytes of JavaScript that you're transferring over the wire. You can use several techniques to lazy-load JavaScript, including:

  • Component-level code splitting
  • Route-level code splitting

With component-level code splitting, you can move individual components into separate JavaScript chunks. On particular events, you can load the relevant scripts and render the components.

With route-level code splitting, however, you move entire routes into independent chunks. When users transition from one route to another, they have to download the associated JavaScript and bootstrap the requested page. These operations can lead to significant delays, especially on slow networks.

Prefetching JavaScript

Prefetching allows the browser to download and cache resources that the user is likely to need soon. The usual method is to use <link rel="prefetch">, but there are two common pitfalls:

  • Prefetching too many resources (overfetching) consumes a lot of data.
  • Some resources the user needs may never be prefetched.

Predictive prefetching solves these problems by using a report of users' navigational patterns to determine what assets to prefetch.

Prefetching example

Predictive prefetching with Guess.js

Guess.js is a JavaScript library that provides predictive prefetching functionality. Guess.js consumes a report from Google Analytics or another analytics provider to build a predictive model that can be used to smartly prefetch only what the user is likely to need.

Guess.js has integrations with Angular, Next.js, Nuxt.js, and Gatsby. To use it in your application, add these lines to your webpack configuration to specify a Google Analytics view ID:

const { GuessPlugin } = require('guess-webpack');

// ...
plugins: [
   // ...
   new GuessPlugin({ GA: 'XXXXXX' })
]
// ...

If you're not using Google Analytics, you can specify a reportProvider and download data from your favorite service.

Integration with frameworks

To learn more about how to integrate Guess.js with your favorite framework check out these resources:

For a quick walkthrough on the integration with Angular, check out this video:

How does Guess.js work?

Here's how Guess.js implements predictive prefetching:

  1. It first extracts data for the user navigational patterns from your favorite analytics provider.
  2. It then maps the URLs from the report to the JavaScript chunks produced by webpack.
  3. Based on the extracted data, it creates a simple predictive model of which pages a user is likely to navigate to from any given page.
  4. It invokes the model for each JavaScript chunk, predicting the other chunks that are likely to be needed next.
  5. It adds prefetching instructions to each chunk.

When Guess.js is done, each chunk will contain prefetching instructions similar to:

__GUESS__.p(
  ['a.js', 0.2],
  ['b.js', 0.8]
)

This Guess.js-generated code is telling the browser to consider prefetching chunk a.js with probability 0.2 and chunk b.js with probability 0.8.

Once the browser executes the code, Guess.js will check the user's connection speed. If it's sufficient, Guess.js will insert two <link rel="prefetch"> tags in the header of the page, one for each chunk. If the user is on a high-speed network, Guess.js will prefetch both chunks. If the user has a poor network connection, Guess.js will only prefetch chunk b.js since it has a high probability of being needed.

Learn more

To learn more about Guess.js, check out these resources: