Using Turbolinks with Vue

Posted on Updated on Vue.js by Gergő D. Nagy

Turbolinks is an amazing tool. It’s really easy to use, makes things faster, and the best part, you basically need nothing to change on your back-end to integrate it. However, there are some small tweaks that we might do after using Turbolinks. Let’s see!

Preparation

Before doing anything, let’s step back and take a look over the concept and what do we need to do to make it work well.

The way Turbolinks works is very simple. When you click a link, it prevents the default action – which is navigating to the link – and sends an AJAX request to the given endpoint. Then it grabs the response extracts the <body> of the response and replaces it with the current view’s <body>. Also, it will update the title of the site as well.

This is all good and easy. But, often we put our JavaScript before the closing body tag. This means when Tublolinks replaces the content we will load the same JS over and over, while we could save those requests easily.

The first thing to do is moving our JS to the <head> tag and wrap the functionality in an event listener. This means when Turbolinks will finish loading the page, it will trigger the proper event and we can reuse the JavaScript as it would be the initial page load.

Integrating Turbolinks with Vue

By default, Tubolinks does not work with Vue, because when we reload the page with the new DOM we lose the reactivity and the bindings. So, we need to bind our Vue instance mounting to an event listener as well. We will use the turbolinks:load event.

My solution is a slightly simplified version of the https://github.com/jeffreyguenther/vue-turbolinks repository.
// Turbolinks
import Turbolinks from 'turbolinks';
Turbolinks.start();

// Vue
import Vue from 'vue';

document.addEventListener('turbolinks:load', () => {
    new Vue({
        el: '#app',

        beforeMount() {
            if (this.$el.parentNode) {
                document.addEventListener('turbolinks:visit', () => this.$destroy(), { once: true });

                this.$originalEl = this.$el.outerHTML;
            }
        },
        destroyed() {
            this.$el.outerHTML = this.$originalEl;
        }
    });
});

So, what is going on? When the turbolinks:load – which means the new DOM was loaded – event is triggered we initialize the Vue instance. When we “navigate” off the page, we destroy the instance.

Disable Turbolinks for Same-Page or Empty Links

Another thing that we would pay attention to is the anchor links – like #some-el or #. Turbolinks will reload the page for those links, but probably this is not what we want. Fortunately, we can disable links for Turbolinks using the data-turbolinks=”false” attribute. Let’s create a small script in the <head> tag and disable those links after the page was loaded.

document.addEventListener('turbolinks:load', function (event) {
    document.querySelectorAll('a[href^="#"]').forEach(function (el) {
        el.setAttribute('data-turbolinks', false);
    });
});

With this, we prevent all the links that start with a # to trigger Tubolink, so no unnecessary page loads are triggered.

Summary

As we can see, integrating Turbolinks is really simple, even if we use a framework like Vue. This approach will really speed up our site because we load the CSS and JS only once, then we just reuse what we already loaded. Also, listening to the proper events, we can use our JS as it would be a normal page load.

If you want to dig deeper, visit the documentation of Tubolinks: https://github.com/turbolinks/turbolinks

Need a web developer? Maybe we can help, get in touch!