Shared publicly  - 
 
My Problem With Turbolinks

I made a few snarky comments about Turbolinks recently and figured I should write down my thoughts more clearly.

If you're not aware of Turbolinks, it captures all local links that look like HTML pages, makes an Ajax request for the content, and then replaces the body with the response's body. It does a few other clever things, like extracting and replacing the title, and executing scripts in the response.

Overall, it's a clever way to get some increased speed while still using a traditional server-rendered-HTML architecture.

Caveats

Like any other solution, it comes with some caveats.

Probably the most important one is that normal HTML-rendered pages have their own clean global scope every time a new page is rendered.

This is not a mere quibble: a lot of existing JavaScript operates under the assumption of a clean scope, and a single DOMContentLoaded event. In a perfect world, popular JavaScript plugins would be architected to work well with a solution like Turbolinks, but the assumption of a clean global scope per server-rendered HTML page is baked into a lot of the JavaScript and jQuery libraries that people tend to use.

It is possible to deal with problems like this on a case-by-case basis (see https://github.com/rails/turbolinks/issues/87, for example), but in my opinion, this is going to end up in a game of whack-a-mole as each new patch breaks other valid use-cases.

At the end of the day, unless Turbolinks can perfectly emulate the browser's behavior, attempts to use Turbolinks with third-party JavaScript will either fail often or require an ever-growing library that handles more and more targeted edge-cases.

jQuery Turbolinks (https://github.com/kossnocorp/jquery.turbolinks) is a good example of something that tries to make the solution more transparent,  but introduces problems as it now triggers ready callbacks multiple times, and idempotence is not typically a requirement of ready handlers. I encourage you to review the open and closed issues on these projects to get a sense of the specific kinds of problems that can occur.

The Good

That said, for applications that are willing to carefully think through the requirements of Turbolinks, this solution does provide a nice transitional way to keep building applications without a lot of architectural changes with improved speed.

If you are thinking about using Turbolinks, make sure:

• Your JavaScript is designed to be long-lived across many different
  HTML pages without a refresh
• Your refresh handlers are idempotent. Don't register event handlers
  or other bindings in a refresh handler unless you reliably tear them down.
• 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. If you don't feel comfortable auditing and cleaning up
  third-party code, don't use any. (note that the "turbolinks community",
  such as it is, might vet existing libraries for compliance, and that would
  help).
96
28
James Tucker's profile photoSterling Cobb's profile photoЛев Лукомський's profile photoIgor Alexandrov's profile photo
28 comments
 
I've implemented a TurboLinks-like site in ASP.NET MVC. It's a great technique, but you definitely have to build your JavaScript correctly.
 
Whenever I think of the name "Turbolinks" I envision some animated gif with flashing colors in the background, and some barbaric character like from an anime just screaming "TURBOLINKS!!!!"

On a side note, isn't this what the pjax thing was doing?
 
Recently I used Turbolinks as a library on one particular page that needs to change a lot of things without reloading. Since it's not a client-side app and an isolated use-case, I kept the logic on the server-side template, removed the window.loaded part from Turbolinks source and started explicitly calling for the "turbo" behaviour.
 
This sounds like it could be rather easy to implement poorly, but it's a neat idea.
 
+Stefan Tilkov It suggests that it's a pragmatic solution to a temporary problem because the "right thing" hasn't arrived yet.
 
+Stefan Tilkov Indeed ;)

I'm in favor of "URLs driven by state machines" in general, I'm just not sure that those state machines need to be entirely on the server long-term.
 
+Jean-Philippe Boily The future will be driven by the specific choices browsers make. It's not here yet, so I don't know what the right long-term solution is yet.
 
For what it's worth I'm hoping that Turbolinks comes with an off switch =)
 
+Jean-Philippe Boily it's too experimental, with too many caveats to justify including it by default. If people want turbolinks they should install turbolinks. Including it in the Gemfile communicates a level of drop-in and maturity that is simply not present. 
 
Yeah this seems like far too unusual a feature to have on by default, I suspect there will be a lot of 1paragraph blog posts with the title "How to disable turbolinks in Rails 4" when it finally lands.
 
I basically use the Turbolinks style architecture. It works well with some custom code to initialize each new page based on a convention of "data-page" IDs on the main element route. I also register a lot of live events, scoped on the page ID.

Also I patched radio.js to include a method to clear pubsub state (https://github.com/uxder/Radio/commit/d9b7c93ccc018e437ae98a6cf83652682ba0cfd2), which happens when each new page comes in.

Yes, it's a hack, but it works, gets me free SEO and faster page loading, which isn't really possible with fat-client JS apps on Rails right now. Since DHH has ruled out baking this into Rails 5, it will be down to projects like Meteor to make it happen the right way.
 
Well said. i think turbolinks is potentially useful for some projects... I think Rails is making a huge mistake to make it the default for all projects.

Rails could use a few less moving parts and things that can go wrong, not more. (While the last major such moving part, asset pipeline, is HUGELY useful, and I think I'm glad it's in rails as default -- it is also the number one source of problems for people getting started with rails (or even people experienced with rails!), in my observations.)
 
I`ve tried turbolink in our project, but found some problems - 1) anchors not work and 2) wrong http-referrer. Turbolinks should be mature enough to set it as default.
 
In my opinion, optimizations like this should be left to the browsers.
And also I think a functionality like this should not be in core Rails, it should be in a gem.
 
I think that the first big problem is that the web is full of javascript code that relies on document ready event, and in this case that event is not fired. This problem it´s common to libraries that relies on pushState, like pjax does. Hey, but it´s possible put an entire application relying on this technique (I have a full web app that uses pjax, including GET form submissions).
 
Well, rails is an opinionated piece of software. Your criticism is totally accurate, Yehuda, so let ask ourselves : what is intended with making this the default ?

Javascript has come a long way since rehab, but there is still a copy/paste trend. Sure, people use plugins now instead of actual copy/paste, but the problem is still there : most developers responsible for javascript layer hardly understand javascript.

Turbolinks is not a innocent and transparent change, it will force rails developers to use actual javascript engineer skills, or even : have dedicated javascript developers. I'm totally in favor of that, personally, even if yes, it's a bit rude to impose it as a default without discussing the move with the community.

Well designed javascript plugins do not bind anything on DOMReady. They tell their users to use init methods on DOMReady event. So, the change will be mostly to move initialization to some special turbolinks ready event, and to generalize the use of destructors (which is a shame not to be common place now we often have long run javascript heavy pages). 

That's not much of a change when you understand how DOM and javascript event model works, and that will be a very positive thing if we make sure every rails developer understand that.
 
To me making this enabled by default would be like making all views cached by default. It's gonna cause problems for people and 99% of them don't even need or want it. I can take 5 seconds to add a gem to my big projects, rather than have this as default and annoyance for my smaller projects where I just don't care.
 
Unless it changed, it will be in the generated Gemfile when creating a new Rails app, so you could just remove it from your Gemfile. That said, things might have changed and maybe it won't even be in the Gemfile by default? Dunno.
 
Gosh. Can you guys stop breaking stuff with all this behind-the-scenes magic trickery? If I want to make my application more responsive by employing AJAX techniques I'd do it explicitly. Hacking around like this will just introduce subtle breaks - a click on a link just does not behave like a page reload, etc. Or at least give me an opt-out. How can I disable this Turbolinks joke for good?

Edit: found it. Just get rid of the 'turbolinks' line in application.js and keep adding AJAX when you're ready for it.
 
You have the same problem with BackboneJS with memory management and plugins using the global namespace. 

Can you get around this by using a module type system (AMD) like requireJS? 
 
Turbolinks seems like an interesting idea, but it kind feels like a bit of premature optimization to me though. I also  see it not always playing nice  with existing javascript frameworks.
 
My friend is a big runner and has been having a lot of back pains.  I really hope he can get some relief for it.  I think he has a big race coming hope so he needs it soon.  Do you know of any good doctors to call?  http://www.totalemedical.com
Add a comment...