The People v Turbolinks

written in flatiron school, rails

This week, as part of the Flatiron Students Present series I gave a presentation on the new features coming in Rails 5.. There’s some really intriguing stuff, highlighted by the Railsified websocket goodness of Action Cable. Nestled in there is the news of Turbolinks 3 Turbolinks 5, the latest version of a Rails feature I was totally unfamiliar with.

I was interested to learn more about this unfamiliar thing, so I turned on my internet and delved into some documentation and blogs on the topic, prepared to learn a cool new thing. But I was suprised by what I found: criticism. A lot. Of. Criticism.

People hate Turbolinks. Like…a whole bunch. Even people who otherwise love Rails. It’s like Rails is the Backstreet Boys and Turbolinks is Kevin.

Kevin Richardson was not a beloved Backstreet Boy

Hell, even the creator of Rails seemingly understands the state of Turbolinks, as evidenced by the way he broached the subject in his 2015 Railsconf keynote speech.

David Heinemeier Hensen introducing Turbolinks 3

Clearly there’s a lot of antipathy directed towards Turbolinks, but why? I think it’s important to understand why bad things are bad, either to help fix them or to avoid making the same mistakes again. So in today’s blogpost, I’m going to be taking a deeper look into the bleak edge of hell that is the world of Turbolinks.

Understanding Turbolinks.

So, what do Turbolinks do? From the source:

Turbolinks makes following links in your web application faster. Instead of letting the browser recompile the JavaScript and CSS between each page change, it keeps the current page instance alive and replaces only the body (or parts of) and the title in the head.

That’s rad, right? I want to make my links faster! And thats great that I don’t need to redownload my CSS and JS resources each time I click a link. It seems to me like that would be great for the user experience, especially on mobile devices.

Delving deeper into the nitty-gritty, Turbolinks takes over any llink, sends an AJAX request for the content, and replaces the <body> on your current page with that fresh new content. It’s basically a PJAX request - a portmonteau of pushState and AJAX.

Abandon all hope ye who Turbolink here

So, as I indicated at the top of this blog, there has been a lot of criticism directed towards Turbolinks. It’s like it’s the worst thing on the internet.

…so, in the spirit of ‘terrible things that exist on the internet’, here’s a Buzzfeed-style Listicle of 7 bad things about Turbolinks.

1. Document ready event.

not ready for this

If you’ve spent any time with JavaScript, then you’ve seen the document ready event. It looks something like this:

1
2
3
$( document ).ready(function() {
    console.log( "ready!" );
});

Simply put, it’s a function that is triggered once your document is ready (eg: all your resources have loaded, the DOM is in place, etc). It’s really helpful for a lot of things, and let’s you ensure that none of your JavaScript functions are triggered before you want them to, which could cause problems especially if the user is manipulating elements in the document before its fully ready.

Unfortunately, Turbolinks don’t call this event, as they aren’t calling a direct page reload. Think of all the things that we might include within a document ready event, like .click() listeners. You could end up with a totally inert and non-functional page.

There are gem workarounds (eg: for jQuery), but the problem is there and needs to be addressed on a case by case basis.

2. Global scope does not get wiped.

scope commercial

Turbolinks claims to save time by not reloading your assets. This is true. But assets aren’t the only thing that remain. The global scope is saved too, meaning that even when it seems like Turbolinks has reloaded a new page, your JavaScript scope is persisting. This is problematic because a lot of JavaScript is written under the assumption that global scope is wiped clean everytime a new page is loaded. This can lead to some wonky results with your scripts, as, for example, multiple bindings can pile up on each other.

Here’s an example of someone trouble shooting this very issue. In their case, buttons that look like this on your initial page load:

button issue

…ended up looking this after a Turbolink is used:

button issue 2

3. SERIOUSLY GUYS. GLOBAL SCOPE DOES NOT GET WIPED.

seriously

I’m restating this because it bears restating. GLOBAL SCOPE DOESN’T GET WIPED. You can catch a lot of the issues related to things like bindings and avoid them in your code. But there are more complicated issues. For example, a lot of Backbone applications use window as a global namespace to store variable instances, like a collection, model or view.

This means that as you reload a page with Turbolinks, that collection, model or view persist even as new Backbone applications load, leading to all sorts of failures related to incorrect data or inapplicable DOM event bindings. FUN STUFF Turbolinks.

There are many other issues - like timers and intervals not resetting - but the point stands: Turbolinks not wiping the global scope is a huge bummer.

4. Memory issues

memories

Another issue relates to memory usage. Turbolinks stores the DOM trees of the last 10 pages you’ve loaded. Typically, we are able to ‘forget’ JavaScript applications as we move through a website by automatically destroying things that are not directly referenced.

But Turbolinks saves those DOMS. And those DOMS have bindings. And those bindings reference applications…meaning that it’s possible for your Turbolinks to cause your application to use up to 10x the RAM that it would otherwise. Neato.

Oh…also…the fact that it remembers those DOMs, bindings and applications is also likely to break your app when you go back a page. Double neato.

5. Not necessarily better than AJAX.

not better

In many cases, Turbolinks can be slower than an AJAX call, as Turbolinks returns fully rendered views of the website, rather than a smaller, more targeted string that can be added to your page where you want.

6. Problems with CoffeeScript

coffee bill murray

Another common issue relates to the use of CoffeeScript and Turbolinks. As CoffeeScript encloses your code in an anonymous function that can be triggered multiple times when using a jquery.turbolinks.js file.

7. This programmer installed Turbolinks on their app. You’ll never believe what happens next.

unexpected

At the end of the day, Turbolinks is likely to bring you unexpected consequences. It can introduce the most unexpected of problems into your app, requiring lots of bug squashing, troubleshooting, stack overflow googling, and tearful calls to your parents to let them know that the chances that you’ll have to move back in with them have gone up.