Kelvin Gobo Software Engineer | Technical Writer | Football #MUFC

Faster page load times with link prefetching

6 min read 1790

Faster page load times with link prefetching

As seen from various studies, there is a direct correlation between faster load times and higher conversion rates. When analyzed critically, the reason is simple, users want to get information quickly and when a website takes too long to provide that information, they move on to other alternatives.

We can reduce the chances of users leaving our application by improving the page load times of navigation using link prefetching. Link prefetching is a technique that is used to fetch links in advance which speed up subsequent navigations.

In this article, we’ll look at three libraries that can be used to prefetch links and explore the pros/cons of each one.

Prefetch with link=prefetch

Before we get into the libraries, I want to note that the browser has a built-in method for prefetching links. Some of the libraries discussed in this article use this method under-the-hood while others don’t.

When the browser is done downloading critical resources for the page and not handling much user interactions, it has some idle time. This idle time is when links with <link=prefetch> are fetched and stored in cache. When the user navigates to the link, it’s fetched from the cache which speeds up navigation.

Prefetching a link is as simple as adding:

<link rel="prefetch" href="/journal" as="document">

as=document tells the browser the type of resource to prefetch so it sets the appropriate headers. Other options are style, script, font and more.

When the user navigates to a prefetched page, in the network tab you’ll see prefetch cache under the size column as seen in the screenshot below. You’ll notice the load time is 10 milliseconds so the page appears instantly to the user.

page fetched from cache

If you would rather not have third-party code, you can roll in your own custom solution using this as a starting point.

We made a custom demo for .
No really. Click here to check it out.

One of the limitations of the browser mechanism of prefetching is that it works with only <link> tags. There’s also little you can do for customization and flexibility. For the rest of the article, we’ll look at three different libraries and the method used by each to prefetch links.

InstantClick

From the official documentation, InstantClick is a JavaScript library that dramatically speeds up your website, making navigation effectively instant in most cases. InstantClick works by prefetching links as soon as a link (<a>)is hovered on (for mobile devices, on touchstart) so by the time the user actually clicks the link, the page is already downloaded.

You can get started with InstantClick through a CDN or an unofficial package on npm. From the command line in your project directory, run the command:

npm install --save instantclick

Then use it in your project:

import InstantClick from 'instantclick'

InstantClick.init()

If you are using the CDN, add <script> to your document.

<script src="https://cdnjs.cloudflare.com/ajax/libs/instantclick/3.1.0/instantclick.min.js"></script>

Then initialize it:

<script data-no-instant>InstantClick.init();</script>

You can also pass additional configuration parameters to determine when to start prefetching a link and how long to keep it in the cache:

InstantClick.init({
  preloadingMode: 50, // Mouseover duration before preload is triggered
  preloadCacheTimeLimit: 30000 // How long to cache preloaded pages
});

That’s the basics of what you need to add InstantClick to your application. There are other things you can do which can be found in the documentation.

quicklink

Next, we’ll look at quicklink, which takes a different method to prefetch links. The method can be broken into four steps:

  • Check all the links currently in the viewport (links that are visible using IntersectionObserver)
  • Detect if the browser is not busy (using requestIdleCallback)
  • Check if the user is on a slow connection (with the Network Information API)
  • Prefetch the URLs to the links (using <link rel=prefetch> or XHR or fetch)

Getting started is as simple as adding <script> with a CDN link to the bottom of your document. quicklink can also be installed via npm.

To install via npm:

npm install --save quicklink

Or using cdn:

<script src="https://cdnjs.cloudflare.com/ajax/libs/quicklink/2.0.0/quicklink.min.js"></script>

Then initialize it like so:

quicklink.listen();

There are other configuration options that can be passed during initialization. Some of them are:

quicklink.listen({
  timeout: 4000, // defaults to 2 seconds
  el: document.getElementById('carousel'), // DOM element to observe for viewport links
  origins: ['example.com'], // list of origins to allow to prefetch from, defaults to hostname
  priority: true // defaults to low-priority
});

The entire library weighs less than < 1kb minified and gzipped so it’s quite lightweight.

Guess.js

Out of all the libraries covered, Guess.js requires the most overhead setup cost. This, in part, is due to the data-driven method used to determine the links to prefetch. Another important factor is the development environment, framework (Angular, Nuxt.js, Gatsby, Next.js) or static site? This second part is important as the development environment determines the setup.

Let’s look at an example with the Nuxt.js framework. Nuxt.js transforms every *.vue file in the pages/ directory to a route. Assuming we have a structure like:

pages/
├── about.vue
├── example.vue
├── index.vue
└── media.vue

This generates the following routes:

/about
/example
/
/media

To use guess.js with Nuxt.js, install guess-webpack as a devDependency:

npm i -D guess-webpack

Then inside nuxt.config.js, add this snippet:

import { readFileSync } from 'fs'
import { GuessPlugin } from 'guess-webpack'

export default {
  ...
  build: {
    ...
    extend(config, ctx) {
      if (ctx.isClient) {
        config.plugins.push(
          new GuessPlugin({
            reportProvider() {
              return Promise.resolve(JSON.parse(readFileSync('./routes.json')))
            }
          })
        )
      }
      ...
    }
  },
  // Nuxt > v2.4.0
  router: {
    prefetchLinks: false
  }
}

Nuxt.js v2.4.0 uses quicklink by default so we override it with prefetchLinks: false. Create a file routes.js in the same directory as nuxt.config.js and add the following:

{
  "/": {
    "/example": 80,
    "/about": 20
  },
  "/example": {
    "/": 20,
    "/media": 0,
    "/about": 80
  },
  "/about": {
    "/": 20,
    "/media": 80
  },
  "/media": {
    "/": 33,
    "/about": 33,
    "/example": 34
  }
}

This file is a sample file which shows the number of times users have gone from one route to another. For example, if we look at the last object, we’ll see that from /media, there were 33 sessions in which users have visited /, another 33 sessions which users visited /about and 34 sessions which users visited /example.

Guess.js takes this data and builds a model to predict which links to prefetch based on the probability of the user navigating to that page next. Guess.js also allows you to consume real-world data from analytics tools like Google Analytics. This real-world usage makes prefetching links more accurate and efficient since it’s based on real-world data. You can see how to configure Google Analytics with Guess.js and Nuxt.js here.

Statistics and trends

npm downloads for instantclick, quicklink, and guess-webpack

As can be seen from the graph above, quicklink and guess-webpack (guess.js) are the most downloaded libraries in the last 6 months with quicklink overtaking guess.js around May this year. InstantClick has the lowest downloads on npm and this may be attributed to the fact that it’s not an official package.

github stats for instantclick, quicklinks, and guess-webpack

The GitHub statistics are closer as can be seen from the table above. quicklink has 8,433 stars (the most) and 28 issues (the least) at of this time of writing. It’s also the smallest in terms of size (< 1kb). Guess-webpack – the npm package for guess.js – is the largest in terms of size (1.2mb). InstantClick has the most issues on GitHub (50) and looking at the last time it was updated, it seems it’s no longer actively maintained.

Developer experience

The table below gives insight into some factors to consider before deciding which one to pick:

Library Documentation Functionality Takeaways Final verdict
InstantClick Well documented. The documentation explains the technique used to prefetch links. It also shows how to add it to static websites and different configuration options that are available. Fails to prefetch link if the mouse is removed before prefetching is complete. However, this does not break navigation and the link can be prefetched when next the user hovers on it. Can be quickly added to a project with a few tweaks. It has a few configuration options which give some control to how links get prefetched. It’s not actively maintained so you may consider one of the other alternatives if you don’t want to dig into the source code. It does not look like it’s actively maintained so there may not be enough support if one runs into issues. All things considered, it is stable and works in a predictable manner.
quicklink The documentation shows how to get up and running with both static websites and using a framework. There are also recipes for different use cases. It works as described. As soon as links enter the viewport, it starts prefetching them. It may not prefetch links on slower connections to preserve user bandwidth. It’s very configurable and integration is relatively painless. The library is developed by the Google Chrome team and it’s still actively maintained so there is good support from the community if you run into any issues. It’s the smallest, in terms of size, amongst the three libraries but it’s actively maintained so there’s support in case challenges arise. Considering all factors, it’s a solid bet for any project.
Guess.js The library is well documented. There are examples of how to set up the library in different frameworks and environments. Prefetched links with a high probability of getting clicked based on analytics data gathered over time. While it takes some time to set up, it’s worth the trouble. A good example is an ecommerce application. Users on the cart page are very likely going to the checkout page. Guess.js will build a model from your analytics data and smartly prefetch the checkout page, based on real-world data of your users! It’s an exciting library and the use cases go beyond prefetching links. The previous libraries are probably better suited for small to medium-sized websites. However, the benefits of prefetching links based on real-world data in large applications will be invaluable.

Conclusion

In this article, we’ve covered three libraries that can be used to prefetch links as well as looking at the methods they use to determine which links to prefetch. We also looked at the inbuilt method of prefetching links.

The library you use comes down to the project you are working on. We’ve seen the pros/cons of each library so you can decide which best suits the project you are working on. Whichever library you choose to use, it will ensure that your links are prefetched which will improve the speed of navigation for your users.

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.
Kelvin Gobo Software Engineer | Technical Writer | Football #MUFC

Leave a Reply