Turbolinks Cheatsheet
A cheatsheet for the often confusing behaviour of Turbolinks.
How it works
When you follow a link, Turbolinks automatically fetches the page:
- Swaps in its
<body>
- Merges its
<head>
…without incurring the cost of a full page load
Allows the server to respond with a full HTML page.
Works in all modern desktop and mobile browsers. Depends on the
- HTML5
History
API Window.requestAnimationFrame
In unsupported browsers, Turbolinks gracefully degrades to standard navigation.
Installation
<script> tag or a
traditional concatenated JavaScript bundle
|
Automatically initializes itself when loaded
|
CommonJS or AMD module
|
Require the module, then call the provided start() function.
|
Ruby on Rails
|
Can use the turbolinks RubyGem
to install Turbolinks
# Gemfile
'turbolinks', '~> 5.2.0’
// application.js
//= require turbolinks
|
Troubleshooting
First identify if it’s a problem with:
Page Load:
- Initial page load (Uncommon - basically standard browser behaviour)
Advance or Replace:
- Displaying the preview of an application visit (flash of content or styling when navigating to pages the browser has already been to, or using the browser’s Forward button)
- After new page has been downloaded and applied
Restoration:
- Retrieving page from cache for restore visits (using the browsers Back button)
and then consult the relevant part of the table below.
Cheatsheet
Type of visit
|
Page Load
|
Advance or Replace
|
Restoration
|
|
Occurs when
|
First page is loaded or browser is refreshed
|
Default: Clicking <a href> to the same
domain, or calling Turbolinks.visit(location)
Using replace instead of advance:
<a href="/edit" data-turbolinks-action="replace">Edit</a>
Turbolinks.visit("/edit",
{ action: "replace" })
|
Browser’s Back or Forward buttons
Internal operation: don’t annotate links or invoke Turbolinks.visit with an
action of restore.
|
|
Disabling
|
|
Limit Turbolinks to only a certain path across entire page
Only load same-origin URLs that are prefixed with this path.
<head>
...
<meta
name="turbolinks-root" content="/app">
</head>
Disable for part of document
<a href="/" data-turbolinks="false">Disabled</a>
<div data-turbolinks="false">
<a href="/">Disabled</a>
</div>
Re-enable when ancestor has opted out:
<div data-turbolinks="false">
<a href="/" data-turbolinks="true">Enabled</a>
</div>
Cancel at runtime
Listen to event turbolinks:before-visit
and use event.data.url (or $event.originalEvent.data.url,
when using jQuery) to decide whether to call event.preventDefault().
Disable showing a preview (if one is available) while
page is being refetched (still used for restoration visits):
<head>
...
<meta
name="turbolinks-cache-control" content=“no-preview">
</head>
|
Disallowing caching
<head>
...
<meta
name="turbolinks-cache-control" content="no-cache">
</head>
Force a full reload:
<head>
...
<meta name="turbolinks-visit-control" content="reload">
</head>
Cancel at runtime
Does not fire turbolinks:before-visit, so can’t be cancelled in this way
|
|
Navigation
|
|
Prevents the browser from following the link
Uses the History API to
push a new entry onto the browser’s history stack (changes current URL): history.pushState.
Request:
Always requests the new page using XMLHttpRequest
|
Discards the topmost history entry: history.replaceState
|
|
Scroll Position
|
|
If location includes an
anchor, attempts to scroll to the anchored element. Otherwise, it will scroll to the
top of the page.
|
Saves scroll position before navigating away and automatically returns to this saved
position on restoration visits.
|
|
Events & Event listeners
|
turbolinks:load is fired in addition to
standard:
|
Can’t depend on a full page load to reset your
environment every time you navigate.
Handle before page change
document.addEventListener("turbolinks:before-visit",
function() {
// ...
})
Handle after page change
turbolinks:load is fired
again after every page change
document.addEventListener("turbolinks:load",
function() {
// ...
})
|
Copies the page to cache using cloneNode(true),
so when it’s returned from the cache, attached event listeners and associated data are
discarded.
Handle cache push
E.g. Reset forms, Collapse expanded UI elements, Tear down third-party widgets
document.addEventListener("turbolinks:before-cache",
function() {
// ...
})
Handle cache pop
Turbolinks adds a data-turbolinks-preview
attribute to the <html> element when
it displays a preview from cache.
if (document.documentElement.hasAttribute("data-turbolinks-preview"))
{
// Turbolinks is displaying a preview
}
|
|
Rendering
|
General
|
|
Will render a preview of the pagefrom cache immediately after the visit starts, if
possible
|
Renders copy of the page from cache
without making a request if possible
|
window and document objects
|
Reloaded from clean state
|
Persisted (No change)
Retain their state across page changes, along with other
objects you leave in memory.
|
||
<html>
|
|
Persisted
(No change)
Adds a data-turbolinks-preview
attribute when displaying a preview from cache
|
Replaced
Merge current document contents with cached document
Mark elements as permanent so they’re not reverted
when the user navigates back (e.g. shopping cart counter):
<div id="cart-counter"
data-turbolinks-permanent>1 item</div>
|
|
<head>
|
Browsers loads and evaluates any <script>
elements
|
Merged
Appends any new <script> elements in
the new page’s <head>
which aren’t in the current one (causing them to be loaded and evaluated)
Load your application’s JS bundle using <script> elements in
the <head> of your
document to avoid reloading them with every page change.
Force page reload if assets change
Track asset URLs in <head> between pages
and automatically issue a full reload if they change
<head>
...
<link rel="stylesheet" href="/application-258e88d.css" data-turbolinks-track="reload">
<script src="/application-cbd3cd4.js" data-turbolinks-track="reload"></script>
</head>
|
||
<body>
|
Replaced
Evaluates <script>
elements in a page’s <body> each time it
renders the page.
Use inline body scripts to:
Don’t use to (use the turbolinks:load
event instead):
Annotate <script>
elements with data-turbolinks-eval="false"
if you do not want Turbolinks to evaluate them after rendering.
|