Turbolinks is an optimization that increases the perceived performance by being smart about switching pages and reloading assets in your app. Unlike conditional GET requests, it doesn't require any changes to the Ruby code in your Rails app itself. Turbolinks 5 is a JavaScript library that works everywhere (even without Rails, like on static pages) and degrades gracefully on unsupported browsers.
Turbolinks 5
Turbolinks has been bundled with Rails and included in new applications by default since Rails 4. Rails 5 ships with Turbolinks 5, which is a rewrite of what's now called Turbolinks Classic.
Although it ships with Rails, the new version of Turbolinks is a pure JavaScript library that can be used on any HTML page putting it in a <script>
tag on the page, or including it into the app's JavaScript bundle.
When included, Turbolinks will automatically find all links that point to the same domain, and attach a click event listener. Any clicks on those links will be intercepted. Instead of following the links like normal, it request the linked page in the background via JavaScript using XMLHttpRequest
. Then, four things happen:
- A copy of the current page is stored in Turbolinks' cache to be used later
- It replaces the current page’s
<body>
with the<body>
from the XHR result - It merges the current page’s
<head>
with the<head>
from the XHR result - It changes the URL in the browser using the History API
By merging the <head>
tags, the browser doesn’t have to reload and rerender assets like CSS and JavaScript files that are present on both pages. This can speed up your app significantly, especially if you have a lot of assets that are reused on most of your pages.
In a fresh Rails 5 app with some views, you can see Turbolinks in action by navigating around by clicking links and pressing the back button. In your browser's network tab, you'll see requests for pages loaded through Turbolinks marked as "xhr". Also, your assets won't be reloaded for every request.
Caching and page previews
To speed up subsequent requests to the same page, Turbolinks maintains a cache of recently visited pages. This allows rendering the previous page immediately when pressing the back button, for example.
To speed up the perceived performance of slow pages, Turbolinks will show a preview of the page if it exists in the cache. After clicking the link, the cached version is shown while the fresh version loads.
Caveats
Turbolinks reimplements some of your browser's default features, so some things work differently with Turbolinks enabled than without.
turbolinks:load
and <script>
tags
Since the page isn't refreshed after every link click, loading JavaScript on page load using window.onload
or DOMContentLoaded
doesn't work anymore. To fix that, Turbolinks supplies the turbolinks:load
event, which you can use instead:
1document.addEventListener("turbolinks:load", function() {
2 // ...
3})
Browser loading states
When switching between pages, the browser won’t show the loading indicator in your browser because the request is executed in the background.
In an attempt to fix that, Turbolinks will show a blue bar (which can be styled with CSS) at the top of the page after 500 milliseconds to indicate that the page is loading.
$ rails new --skip-turbolinks
?
Turbolinks 5 has come a long way since Turbolinks Classic, when Turbolinks seemed to be that thing you skipped when generating a new Rails app. Being a gracefully degrading pure JavaScript plugin that doesn't depend on Rails now, it works out of the box for most apps, if you keep the caveats in mind.
In return, Turbolinks gives a nice speed boost and prevents your static assets from being reloaded on every page view, which saves some network requests. When generating a new Rails app, try keeping Turbolinks in to see what it does. On existing apps, give Turbolinks a try!
That concludes our overview of Turbolinks. Are you using Turbolinks in any of your apps? We'd love to hear from you! Also, we're curious to how you liked this and previous articles in AppSignal Academy, or what you'd like to read about next at @AppSignal.