Turbolinks: Two Add-ons That Make It More Magical

Posted 15 days ago by @jessethanley


(If you're not sure what Turbolinks is, read the Github repo to get up to speed β€” it's not just for Ruby on Rails projects too, I've implemented it on Shopify, my WordPress affiliate sites and a few Laravel projects).

For the longest time, there has been a meme in the Ruby on Rails community that goes:

"What's the first thing you do when you start a fresh Rails app?"

"Uninstall Turbolinks".


And whilst in the beginning, I did exactly that, I now find myself realising that it was short sighted and, frankly, childish.

When you commit to ideas behind Turbolinks, you realise that it's perhaps one of the most liberating Javascript libraries for people building apps on the web and is nothing short of magic. 

Using it, I've been able to pull off some really interesting interactions in my products (primarily developing Bento) that I would have thought would only have been possible if I'd been building an SPA (single page application) using Vue, Angular or React. 

When I've demoed it to others, I've often been asked what JS framework I've been using and many have been shocked to hear it's just Rails w/ some Turbolinks sprinkled on it. 

In this post, I want to include two minor tweaks that we've added to Turbolinks to make it even better.

First, let's improve how to reload a page with Turbolinks.

One of the magical things about Turbolinks is that when you run refresh the page with, say "Turbolinks.visit(location.toString());", it will just replace your current screen's <body></body> tags with new HTML from the refresh.

Net effect being new content, without any flickering!

The problem that people run into is that by default it doesn't store scroll position, so the user will jump to the top of the page when you fire it off. 

Not the nicest experience.

So, this snippet below stores the scroll position, reloads the page, and the user will just see the load bar up top. 

;(function () {
  var scrollPosition

  document.addEventListener('turbolinks:load', function () {
    if (scrollPosition) {
      window.scrollTo.apply(window, scrollPosition)
      scrollPosition = null
    }
  }, false)

  Turbolinks.reload = function () {
    scrollPosition = [window.scrollX, window.scrollY]
    Turbolinks.visit(window.location, { action: 'replace' })
  };
})();
Best used on a page with tables, data that updates regularly or reporting screens. For Bento, we refresh the "Live Events" page every 5 seconds. People think it's live, but really, it's just firing off Turbolinks.reload()!

The second script is perhaps my favourite snippet I include in all my projects (grab it here β€” too long to include in this post).

For the most part, despite huge increases in both bandwidth, hardware and speed, websites don’t get much faster after you hit a certain scale.

We've learned this the hard way with Bento serving millions of requests per month.

What becomes the biggest problem is latency which is much harder to optimize for. It's the bottleneck of most websites aggressively optimising for speed.

Luckily for us, this post is focusing on delivering content and not Javascript code like Bento and we have Turbolinks to help.

The code above, turbolinks_prefetch.coffee, attempts to resolve this problem by loading pages in-between the difference of someone hovering over a link and actually clicking the link.

You'd be shocked how much time actually passes between that. 

From all the tests I've run on my sites, it's a good 200 - 500ms. 

That's enough to load a full page! 

After adding it, you'll notice pages will load a good factor faster than they were previously because they're now readily available in your cache after they've been hovered over.

It operates very similarly to Instantclick.io but not as delightful as the solution I've covered above. 

Anyway, hope you guys enjoyed this quick piece. If you had any questions, just ask on Twitter. Here to help!