DEV Community

loading...
Cover image for Using Turbolinks to speed up your site

Using Turbolinks to speed up your site

Sunny Singh
Creating content and code
・4 min read

Originally posted on the Ninjality blog.

In a world of single-page apps (SPAs) that are rendered by the browser, it is hard to consider building any other way; you get a lot of benefits such as performance of almost instant-loading pages. However, there are still good use cases for building traditional server-rendered websites such as those powered by a CMS (content management system) like WordPress. At Ninjality, we recently redesigned and chose to use October CMS to help with managing content. Choosing a CMS doesn't mean that you have to give up on the benefits of SPAs, so I want to show how we used the Turbolinks library to make our site feel like it was built in a modern JavaScript framework.

Understanding PJAX

To help better understand what Turbolinks does, it is important to learn the concept of PJAX which has actually been around for many years. PJAX stands for pushState + Ajax, and uses both those technologies to intercept link clicks so that JavaScript is able to update the URL and load content via Ajax. Initially, both Turbolinks and PJAX required backend integration so that the Ajax responses would only contain the page title and content. While this is still ideal for performance, Turbolinks as a JavaScript-only library simply works out of the box by manually parsing the title and content out of the full HTML. A fun fact if you're new to Turbolinks is that it used to exist as a Rails-only Ruby gem, and PJAX had a JS library that relied on jQuery. Now, Turbolinks is a standalone library that you can integrate into any website.

Installing Turbolinks

You simply need to include the Turbolinks JS library into your page. View the README for instructions, but let's assume that you're using some form of bundler with npm:

npm install turbolinks --save
Enter fullscreen mode Exit fullscreen mode

Now you need to import and initialize Turbolinks:

var Turbolinks = require('turbolinks')

Turbolinks.start()
Enter fullscreen mode Exit fullscreen mode

If your site is very simple, then you're already done. Most of the time you'll need some extra setup though.

Integrating your website

If you already have some JavaScript running on your site, then you're most likely listening for a page load or domready event. In the case of Ninjality, we have code highlighting, smooth scroll, image zoom, share buttons, and many other libraries that would normally look something like this:

document.addEventListener('DOMContentLoaded', function () {
  // initialize scripts....
})
Enter fullscreen mode Exit fullscreen mode

However, now that pages can be loaded over Ajax, we need another event to know when those pages load, otherwise our scripts will only fire once (when the user manually visits the site for the first time). Thankfully Turbolinks provides such an event:

document.addEventListener('turbolinks:load', function () {
  // initialize scripts....
})
Enter fullscreen mode Exit fullscreen mode

As you can see, a simple change from DOMContentLoaded to turbolinks:load will fix your scripts. Well, most of them. Let's fix some common gotchyas in the next section.

Some common gotchyas

You're most likely using Google Analytics, Disqus, social widgets, and other third-party tools that are loaded via inline <script> snippets. How do you transfer these over to the turbolinks:load event?

You'll need a dynamic script loader. The load-script library is what we use on Ninjality. As usual, install it through npm:

npm install load-script --save
Enter fullscreen mode Exit fullscreen mode

Now you can use Google Analytics again:

var Turbolinks = require('turbolinks')
var loadScript = require('load-script')

Turbolinks.start()

document.addEventListener('turbolinks:load', function () {
  // initialize scripts...

  // Google Analytics
  if (typeof ga === 'undefined') {
    loadScript('https://www.google-analytics.com/analytics.js', function () {
      window.ga = window.ga || function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date
      ga('create', 'YOUR-TRACKER-ID', 'auto')
      ga('send', 'pageview')
    })
  } else {
    ga('send', 'pageview')
  }
})
Enter fullscreen mode Exit fullscreen mode

Since we integrate Facebook Comments, the same had to be done here as well:

if (typeof FB === 'undefined') {
  loadScript('https://connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.8&appId=YOUR-FB-APP-ID')
} else {
  FB.XFBML.parse()
}
Enter fullscreen mode Exit fullscreen mode

Unfortunately, we had to take an extra step to get Facebook Comments to work properly. This meant including the data-turbolinks-permanent attribute on <div id="fb-root">:

<div id="fb-root" data-turbolinks-permanent></div>
Enter fullscreen mode Exit fullscreen mode

Finally, the last gotchya you need to be careful of is when including scripts in the <body>. Make sure that you add the data-turbolinks-eval="false" attribute:

<script src="bundle.js" data-turbolinks-eval="false"></script>
Enter fullscreen mode Exit fullscreen mode

While Turbolinks claims to properly resolve inline scripts, we had issues with our JavaScript running multiple times during page navigations.

Closing thoughts

For many content-based websites that need administrative features, a front end framework like React is overkill. October CMS allows us to have a simple setup with search engine optimization and an admin interface in mind. By integrating Turbolinks, we also were able to compromise between the benefits of a server-rendered website and a single-page app. Do keep in mind that Turbolinks is not a replacement for building an SPA, because you don't get other benefits like state management or quick UI development with Turbolinks. Leave a comment or tweet @NinjalityDesign if this article helped you integrate Turbolinks into a project!

Discussion (1)

Collapse
ahmedam55 profile image
Ahmed Mahmoud

Such an amazing article. You know the first time my tech lead used it, I felt like, that's magic :)