Dan Bradbury

Ramblings, rants, and musings of an engineer

Into the Abyss With Turbolinks

Previous attempts to adopt turbolinks during upgrades or new projects led me to the conclusion that I have a burning hatred for everything the project stands for (rage hatred is the worst kind..). From conversations with other Rails folks + former CTOs it seemed like turbolinks was something I could avoid without batting an eyelash (see comparisons to Windows 8 decision making or just ask a local Rails expert what their experience with turbolinks has been like)

As someone who previously ignored the efforts being made by DHH and the core team I would just start a new project with --skip-turbolinks to ensure my own sanity and continue with the hammering.

Since I’m a bit late to this conversation it’s nice to read posts like Yahuda Katz’ problem with turbolinks and 3 reasons why I shouldn’t use Turbolinks to get my hopes and dreams crushed.. Here is just the beginning of the headache that one can look forward to if they are to continue down through the thorns

Duplicate Bound Events

Because JavaScript is not reloaded, events are not unbound when the body is replaced. So, if you’re using generic selectors to bind events, and you’re binding those events on every Turbolinks page load. [This] often leads to undesirable behavior.

Alright so to be honest this isn’t that bad. People can bitch about global state all they want but as someone who enjoys thinking in a “game loop” I don’t mind this and feel like I can easily write my own code to these standards

Audit Third-Party code

You audit all third-party code that you use to make sure that they do not rely on DOM Ready events, or if they do, that they DOM Ready events are idempotent.

And this is where it starts to get fun.. I just stumbled upon a bug that reared its head beacuse of these two issues and I wanted to post a solution that I may find myself using more moving forward..

Imagine we are using typeahead.js we want to go ahead and initialize our typeahead input on a given page. Here’s what the JS might look like

1
2
3
4
5
6
7
8
9
  $('#searchBar .typeahead').typeahead({
    hint: true,
    highlight: true,
    minLength: 2
  },
  {
    name: 'estados',
    source: matcher(items)
  });

A pretty harmless call that you are probably going to copy paste in to try the first time you mess with typeahead.js. It works and you move on.. But be careful because turbolinks will give you some intereseting behaviour if we navigate between the page that has this piece of JS and another page. .

Turbolinks will invoke this each time the page is “loaded”. Because of this we will spawn a new instance of the typeahead input and the associated hint div.. For some reason (one I don’t care to look into) typeahead.js will spawn a new instance and hide the others rather than truly cleaning up. No matter what we are left to fend for ourselves in the wilds of turbolinks so we search for a solution.

I figure we can just handle global state a little better than your typical inline JS would. To do this we simply wrap the initializer in a conditional to verify the number of typeahead divs that are present on the screen. With proper naming we should be able to expand this approach to multiple typeahead instances.

1
2
3
4
5
  if($('.typeahead.tt-input').size() < 1) {
    $('#searchBar .typeahead').typeahead({
      ...
    }
  }

With that extra check we are able to handle the global state that turbolinks will create when natrually navigating and attempting to speed up our page.

A recent webcast featuring DHH got me thinking about how simple the problem of a web application really is. The server demands are not a problem whatsoever (30ms response times are all you need to be perfect anything lower is not truly noticable or necessary). We have an issue when it comes to how the rest of the “page-load” occurs for the user.

We all know the “hard refresh” links, the ones that clearly jump you to a new page with new content. Loading a new page is the same old same old that we’ve been doing since we could serve shit up. Of course the new way is the “one page app” that allows the user to navigate without ever having to disengage from the page they were on. IMO the trend is getting a bit insane (always felt the JS community was a bit heavy handed with trying new things..) and trying to keep up with the latest quarrels and trends is tiring. Where is the solution to the seamless application?

It’s clear that some will say Ember or React are the way forward to building beautiful apps that will take over the world but I’m not sure I believe a JS Framework is what will carry an application. So why learn all that unecessary complexity when HTML5 is here?

If Turbolinks lives up to the into of the README I will be a happy Rails camper.

Turbolinks makes navigating your web application faster. Get the performance benefits of a single-page application without the added complexity of a client-side JavaScript framework. Use HTML to render your views on the server side and link to pages as usual. When you follow a link, Turbolinks automatically fetches the page, swaps in its , and merges its , all without incurring the cost of a full page load.

C’mon Turbolinks don’t let me down again..

Comments