Help us understand the problem. What is going on with this article?

turbolinksチートシート

なんか速くなるやつ、程度の理解だったturbolinksを調べてみました。

「(ロード制御がややこしいので)静的なサイトに関してのみ使うべし」のような意見を多く見かけたのですが、
機能を俯瞰してみると本来はSPAの代替(複数ページでフロントアプリを構成する)を意図したツールのように思えました。
react-redux等と組み合わせての運用を検討してみたいところです。

概要

turbolinks = Ajaxによるページ遷移の高速化のためのライブラリ

  • オープンソース / MITライセンス

  • 導入コストが低い

    • サーバ側の特別な対応は不要
    • モバイル環境にも対応
    • ユーザ側から見て、通常のページ遷移と同じように表示される/動作する
  • Rails4で公式採用された

    • バインディング(turbolinks-rails)がデフォルトでGemfileに含まれている

仕組み

turbolinksにおいて、リンクがクリックからページ表示までの一連の流れをVisitと呼ぶ。
Visitは大きく二種類:

  • Application Visits = リンククリックによるページ遷移
  • Restoration Visits = ブラウザの戻る/進むボタンによるページ遷移

Application Visitsの挙動

turbolinksは以下のように動く:

  • 同じドメイン内にリンクする<a href>タグのクリックを監視する
  • クリック時、リンクによるページ遷移を妨害する
  • キャッシュが存在する場合、その内容を一時的にbody上に表示する(キャッシュプレビュー表示)
  • Ajax(XMLHttpRequest)で次のページを取得する
  • 取得したページを、現在のページと置換える
    • <head>はマージする
    • <body>は完全に差し替える
  • スクロール位置を更新する
  • HistoryAPIを操作して、URLを変える(history.pushState.ページ遷移したように見せる)

遷移にあたって今のページと共有するリソース(css/img/js)の再読込が不要となるため、読み込みが速くなる。
なお、フックイベントを使って遷移をキャンセルできる。

Restoration Visitsの挙動

進む/戻る場合、turbolinksはキャッシュを積極的に利用する:

  • キャッシュが存在する場合は、リクエストを出すことなくページを再表示させる
  • スクロール位置は記録されており、遷移時に復元される

Restoration Visitsはリンクを動的にキャンセルできない

導入

Rails(w/ アセットパイプライン)

Railsかつアセットパイプラインを使う場合は、turbolinks-railsをインストールする(最初からGemfileに含まれている)

Gemfile
gem 'turbolinks', '~> 5'
$ bundle install

それ以外

Rails以外、あるいはRailsでもアセットパイプラインを使わない場合はnpmパッケージとしてインストールする。

$ yarn add turbolinks

使い方

開始する

Rails(アセットパイプライン)の場合は、対象のページが読み込むjsファイルにturbolinksをrequireするだけでいい。

app/assets/javascripts/application.js
//= require turbolinks

npmパッケージとして利用する場合は、turbolinksモジュールをimport/requireした上でstart()を実行して開始する。

app/some/other/system/of/spa.js
// Node
var Turbolinks = require("turbolinks")
Turbolinks.start()

// ES6
import Turbolinks from 'turbolinks'
Turbolinks.start()

利用可否を確認する

supportedプロパティで、ブラウザの対応状況を確認できる。
おおむねHistoryAPIに対応している環境であれば動作するらしい。

if(Turbolinks.supported){
  // ...
}

無効化する

jsの再読み込みなどに関してturbolinksによるリンクに問題が生じた場合は、特定のリンクのみ、この機能を無効化できる。

無効化状態は、対象の<a>タグかその親のタグに、data-turbolinksを指定することで制御できる。

直接無効化する
<a href="..." data-turbolinks="false">turbolinksを使わずにリンクする</a>
親によって無効化する
<div data-turbolinks="false">
  <a href="...">...</a>
</div>

historyスタックを無視する

data-turbolinks-action="replace"を指定すると、ページ遷移しても、その履歴がhistory(戻る/進むボタン)に記録されなくなる。

<a href="..." data-turbolinks-action="replace">...</a>

ロードイベントをとる

turbolinksの場合、ページ遷移をてもwindow以下のオブジェクトの状態が保たれる(メモリ上に残る)。
またwindow.onLoadイベントは、最初のページの表示時以外は呼ばれない

そのため変わりに、画面表示時にはturbolinks:loadイベントが発行される。
このイベントを監視することで、ページ遷移ごとの処理を実装できる。

document.addEventListener("turbolinks:load", function(){
    ...
})

その他のライフサイクルイベントをとる

ロード以外にも、turbolinksの挙動に関わるイベントを取得できる。

イベント 内容 備考
turbolinks:load ページの読み込み時 window.onLoadの代替として利用
turbolinks:click turbolinksが有効な<a>タグのクリック e.data.urlでURLの取得可能
turbolinks:before-visit 遷移の開始前(Restorationを除く) ページ取得のキャンセルも可能
turbolinks:visit 遷移の開始直後 -
turbolinks:request-start ページ取得の開始時
turbolinks:request-end ページ取得の終了時
turbolinks:before-cache キャッシュの開始前
turbolinks:before-render ページ表示前 e.data.newBodyで新しい表示内容を取得可能
turbolinks:render ページ表示後 キャッシュプレビューが表示された場合にも呼ばれる

最初のページ以外では実行させない

<script>タグの実行(評価)のタイミングは、それが書かれた場所によって変わる。

  • <head> 内の場合は、その画面がはじめて表示されたタイミングで1度だけ実行される
  • <body> 内の場合は、その画面が表示されるたびに実行される

繰り返し実行されることによる処理の重複を避けるため、data-turbolinks-eval属性を指定する。
falseを設定することで、その<script>タグはturbolinksを開始したページの初回表示時のみ、実行される。

<script src="path/to/src.js" data-turbolinks-eval="false"></script>

ページ遷移しても特定のタグを残す

data-turbolinks-permanentを指定すると、ページが変わってもそのタグを残すことができる。

<div data-turbolinks-permanent>
  ...
</div>

js/cssファイルの更新を監視する

<head>内に記述されたリソースは初回しか読み込まれない。
data-turbolinks-track="reload"を設定すると、遷移時にリソースの更新を確認し、必要に応じてリロードする。

<head>
  <script src="path/to/src.js" data-turbolinks-track="reload"></script>
</head>

動的に制御する

JavaScriptによって動的にページ遷移させることもできる。

// キャッシュを消す(任意)
Turbolinks.clearCache()

// ページ遷移する
Turbolinks.visit(...)

プログレスバーを表示する

turbolinksによる遷移はAjax制御のため、ブラウザのプログレスバーに進捗が表示されない。
代替として、ロード状況を画面の最上部に表示させることができる。

表示させるためにはまずプログレスバーを有効化する。
(公式の説明ではデフォルト有効のことだが、呼ばないと表示されなかった)

Turbolinks.enableProgressBar()

有効にすると遷移時にclass="turbolinks-progress-bar"のタグが挿入されるので、このクラスのCSSスタイルを任意に設定する。

.turbolinks-progress-bar{
  height: 10px;
  background-color: green;
}

参考

morrr
web/モバイルエンジニア。インフラからアプリまで色々やります。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away