Getting Started
    Core Concepts
    Building Features
    API Reference
    Deployment
    Upgrading
    Migrating
    Pro
    Advanced Topics
    Misc
    Shakacode logoShakaCodeDeveloped by

    Copyright 2020 ShakaCode

    Turbolinks and Turbo Support

    React on Rails Updated to support Turbo, August 2024

    Using Turbo

    To configure Turbo the following option can be set: ReactOnRails.setOptions({ turbo: true })

    Turbo is not auto-detected like older Turbolinks.

    TODO: Walk through code changes in PR 1620.

    The following documentation covers older Turbolinks versions (2.x and 5.x). While still supported by React on Rails, we recommend migrating to Turbo when possible.

    React on Rails currently supports:

    • Turbolinks 5.x (e.g., 5.0.0+) - Auto-detected
    • Turbolinks 2.x (Classic) - Auto-detected
    • See Turbolinks on Github

    You may include Turbolinks either via yarn (recommended) or via the gem.

    As you switch between Rails HTML controller requests, you will only load the HTML and you will not reload JavaScript and stylesheets. This definitely can make an app perform better, even if the JavaScript and stylesheets are cached by the browser, as they will still require parsing.

    1. Either avoid using React Router or be prepared to deal with any conflicts between it and Turbolinks.
    2. Use one JS and one CSS file throughout your app. Otherwise, you will have to figure out how best to handle multiple JS and CSS files throughout the app given Turbolinks.
    1. React Router handles the back and forward buttons, as does Turbolinks. You might be able to make this work. Please share your findings.
    2. You want to do code splitting to minimize the JavaScript loaded.

    Installation

    Install Checklist

    1. Include turbolinks via yarn as shown in the react-webpack-rails-tutorial or include the gem "turbolinks".
    2. Included the proper "track" tags when you include the javascript and stylesheet:
      <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => 'reload' %>
      <%= javascript_include_tag 'application', 'data-turbolinks-track' => 'reload' %>

    NOTE: for Turbolinks 2.x, use 'data-turbolinks-track' => true

    1. Add turbolinks to your application.js file:
      //= require turbolinks

    See the instructions on installing from NPM.

    import Turbolinks from 'turbolinks';
    Turbolinks.start();
    Async script loading

    Async script loading can be done like this (starting with Shakapacker 8.2):

      <%= javascript_include_tag 'application', async: Rails.env.production? %>

    If you use document.addEventListener("turbolinks:load", function() {...}); somewhere in your code, you will notice that Turbolinks 5 does not fire turbolinks:load on initial page load. A quick workaround for React on Rails earlier than 15 is to use defer instead of async:

      <%= javascript_include_tag 'application', defer: Rails.env.production? %>

    More information on this issue can be found here: https://github.com/turbolinks/turbolinks/issues/28

    When loading your scripts asynchronously your components may not be registered correctly. Call ReactOnRails.reactOnRailsPageLoaded() to re-initialize like so:

    document.addEventListener('turbolinks:load', function () {
      ReactOnRails.reactOnRailsPageLoaded();
    });

    React on Rails 15 fixes both issues, so if you still have the listener it can be removed (and should be as reactOnRailsPageLoaded() is now async).

    WARNING

    Do not use immediate_hydration: false (React on Rails Pro licensed feature) with Turbolinks if you have async scripts.

    React on Rails will automatically detect which version of Turbolinks you are using (2.x or 5.x) and use the correct event handlers.

    For more information on Turbolinks 5: https://github.com/turbolinks/turbolinks

    Technical Details and Troubleshooting

    CSRF and MIME Type Handling

    • CSRF tokens: Turbolinks 5 changes the head element by JavaScript (not only body) on page changes with the correct csrf meta tag. Be thorough checking CSRF tokens, especially when multiple windows are opened, as the CSRF helper in ReactOnRails needs to work with Turbolinks5.
    • MIME type handling: Turbolinks 5 sends requests with Accept: text/html only (not Accept: */*), which makes Rails behave differently compared to normal requests. For more details on the special handling of */* you can read Mime Type Resolution in Rails.
    • Multiple Webpack bundles: If you're using multiple Webpack bundles, make sure that there are no name conflicts between JS objects or Redux store paths.

    To turn on tracing of Turbolinks events, put this in your registration file, where you register your components.

    ReactOnRails.setOptions({
      traceTurbolinks: true,
      turbo: true,
    });

    Rather than setting the value to true, you could set it to TRACE_TURBOLINKS, and then you could place this in your webpack.client.base.config.js:

    Define this const at the top of the file:

    const devBuild = process.env.NODE_ENV !== 'production';

    Add this DefinePlugin option:

      plugins: [
       new webpack.DefinePlugin({
         TRACE_TURBOLINKS: devBuild,
       }),

    At Webpack compile time, the value of devBuild is inserted into your file.

    Once you do that, you'll see messages prefixed with TURBO: like this in the browser console:

    Turbolinks Classic:

    TURBO: WITH TURBOLINKS: document page:before-unload and page:change handlers installed. (program)
    TURBO: reactOnRailsPageLoaded

    Turbolinks 5:

    TURBO: WITH TURBOLINKS 5: document turbolinks:before-render and turbolinks:render handlers installed. (program)
    TURBO: reactOnRailsPageLoaded

    We've noticed that Turbolinks doesn't work if you use the RubyGem versions of jQuery and jQuery ujs. Therefore, we recommend using the JS packages instead. See the tutorial app for how to accomplish this.

    Show we only install the Turbolinks handlers once