Turbolinks: Leaving the Abyss

Just trying to do things like

<a href=”#” onclick=”alert(1)”>ZZZ</a>

Expected behavior here?.. Scroll to top of the page right? Not if turbolinks is doing its thang.

From my previous write-ups on Turbolinks (1 2) I was pretty understanding about the inherent behavioural differences for all things links.

If I wasn’t aware of Turbolinks I’d be incredibly confused by this incredibly simple bit of code. This time I was lucky enough to spot the Turbolinks loarder bar attempting to do unnecessary work and knew what the issue was

On top of initial confusion the fact that something like href=”#” doesn’t work according to spec is pretty frustrating and difficult to understand.

If we really want a link what do we do

<button> is your friend. Include Bootstrap and link style that SOB if you really want that link feel.. a bit annoying but easy enough to add to a project and remember class="btn btn-link"

The reason that works is because by default Turbolinks is only looking for <a href> links pointing to the current domain (of course we can turn this off w/ data-no-turbolinks='true'

All this additional knowledge for such little gain is not worth it. I don’t care to remember or reason about how Turbolinks will be handling history or trying to optimize potential page loads. Unless I’m building a single page app that has the same feel across all browsers and devices I’m not interested in the additional complexities.

No disrespect or hating on the idea for Rails 5 to include turbolinks by default; it’s understandable that to remain relevant in the app academy days of development folks are looking to build single page apps that will become the next hot thing.

I am officially on the rails new my_app --skip-turbolinks 🚂 now

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

  $('#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.

  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..

Stop Being Lazy and Learn Haml… or another Templating Engine

The desire to write familiar view code, similar to the same html you were writing to support your shitty LAMP apps is completely understandable but it’s time to move on from the glory days..

There seems to be this idea that using erb is “good enough” in all scenarios because so many of web devs are accustomed to seeing their old friend html.. As someone who knowingly opted out of using Haml because HTML always felt like option that would give me the most flexibility. Since the actual engine driving the browser has a simple set of responsibilites (MASSIVE OVERSIMPLIFICATION: fetch a document from a URL and render the contents of that document onto the page) the document that we are going to be providing to the browser’s engine must adhere to standards that allow many browsers to function with their various implementations. Because of this fact debugging/learning a templating engine is actually a walk in the park if your HTML skills are as sharp as they should be..

To be fair; when researching Haml it may not be clear what you are getting yourself into.

<section class=”container”>
  <h1><%= post.title %></h1>
  <h2><%= post.subtitle %></h2>
  <div class=”content”>
    <%= post.content %>
  </div>
</section>

To be honest the above code doesn’t look to be that bad to me but I’ve never really had an “eye for design”. As an additional bonus I know exactly what the browser output is going to be (assuming no CSS + JS messing with things). But let’s take a look at some haml code..

%section.container
  %h1= post.title
  %h2= post.subtitle
    .content
      = post.content

The raw number of keystrokes should be striking to get the same browser output. The declarative simplicity that Haml provides is unbelievable when you consider all the bullshit we deal with when writing HTML. Anyone who written web apps can tell you at least one tail of a missing closed tag.

I was hesitant about writing something that wasn’t what I knew and used for a long time. The notion of “what works for me” is not a good enough reason to write code that is sub par. Since most devs are bright enough folk I don’t think learning Haml is more than a 1 micro-project away from being your new favorite way to write your views.

For more information on Haml check out the Haml Homepage. All links to get started should be easily accessible from there.

The beauty of using haml in every day development is that your code shape will be forced to be much nicer and cleaner. Consider writing a container div with a header, body, and footer. One would hope for clear structure that tells a “foreign eye” exactly what is going on in the given view.

Just imagine the skeleton that would evolve in the html version of this as a clean slate to start from.

<div class="container">
    <div class="header"></div>

    <div class="content">
    ...
    </div> <!-- end of content -->

    <div class="footer"><%= render "footer" %></div>

</div> <!-- end container -->

As anything gets added to this skeleton you hope that the structure stays readable. I think that the forced structure prevents you from being your own worst enemy . Because of this simple fact I am turning into a Haml guy and think a weekend using it will convert any non-believers.