loading...

Turbolinks extend prefetch to speed up your website

huacnlee profile image Jason Lee Originally published at ruby-china.org on ・3 min read

This article shares an extension of Turbolinks for accelerating web page access.

Background

Recently, I discovered InstantClick, a small technique for pre-loading web pages, which can effectively improve the speed of website access.

The general principle is that when the user mouses over the link, the web page will be pre-loaded in the cache by Ajax in advance, and when the user clicks, it will be directly rendered with the previous cache.

So I also tweeted about this:

Rails built-in Turbolinks actually has a similar cache mechanism. When the user clicks the page back and forth, it will use the cache to pre-render it, but it does not preprocess it when the user's mouse is hovered.

I checked and found that Turbolinks' Issue also discussed this turbolinks/turbolinks#313, and I found an implementation Reference, so I encapsulated it, and made improvements to implement an extension of Turbolinks.

https://github.com/huacnlee/turbolinks-prefetch

At the same time, I have additionally adjusted the visit action of Turbolinks in the implementation. If there is already a prefetch action, it will be rendered directly without requesting the page again.

As you can see, currently Ruby China has enabled this feature (Hong Kong server). When the prefetch has an effect, the page is basically opened like a local web page.

How Turbolinks Prefetch works

hover --> [prefetch] --<no cache>--> [XHR fetch] -> [Turbolinks cache.put]
              |
          <exist cache / in fetching>
              |
            ignore

click --<check cache>-- exist --> [isPrefetch] -> [Turbolinks.visit advance] ---> [render page]
             | | |
             | | --async-> [fetch background] -> [render if updated]
             | |
             | <Yes>
             | |--- [Turbolinks.visit restore] --> render -> nothing
          No cahce
             |
             ---> [Turbolinks.visit]

Enter fullscreen mode Exit fullscreen mode

Installation

$ yarn add turbolinks-prefetch

Enter fullscreen mode Exit fullscreen mode

Usage

import Turbolinks from 'turbolinks';
window.Turbolinks = Turbolinks;

import TurbolinksPrefetch from 'turbolinks-prefetch';
TurbolinksPrefetch.start();

Enter fullscreen mode Exit fullscreen mode

When a Prefetch request is made, an additional HTTP header of Purpose: prefetch will be sent. If you need to ignore certain actions, you can use it.

For example, actions such as updating the reading status and the number of visits:

class TopicsController < ApplicationController
  def show
    if request.headers["Purpose"] != "prefetch"
      # Do not update visits during prefetch
      @topic.increment_hit
    end
  end
end

Enter fullscreen mode Exit fullscreen mode

Disable Prefetch for some links

By default, Turbolinks Prefetch will turn on the behavior for all links.

Except for the following situations:

  • Links to different websites (Host / Origin are different);
  • There is a link to open a new window target="_blank";
  • Links with data-remote attribute;
  • There are links with data-method attributes;
  • Links with data-prefetch="false" attribute;

It should be said that you don't need to deal with most of the default situations. The default behaviors like Rails UJS are already handled in Turbolinks Prefetch.

So you can disable prefetch for some links like this:

<a href="https://google.com">Google</>
<a href="/topics/123" target="_blank">Open in new window</a>
<a href="/topics/123" data-method="PUT" data-remote>Put</a>
<a href="/topics/123" data-method="DELETE">Delete</a>
<a href="/topics/123" data-prefetch="false">Disable by directly</a>

Enter fullscreen mode Exit fullscreen mode

GitHub

🎊 Don't hesitate, immediately use it in your projects that already use Tubrolinks, basically seamless support.

https://github.com/huacnlee/turbolinks-prefetch

Discussion

pic
Editor guide
Collapse
dzello profile image
Josh Dzielak 🔆

We had a similar solution but will check out your repository. Thanks for sharing the article and code 🙏