なんか速くなるやつ、程度の理解だった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に含まれている)
gem 'turbolinks', '~> 5'
$ bundle install
それ以外
Rails以外、あるいはRailsでもアセットパイプラインを使わない場合はnpmパッケージとしてインストールする。
$ yarn add turbolinks
使い方
開始する
Rails(アセットパイプライン)の場合は、対象のページが読み込むjsファイルにturbolinksをrequireするだけでいい。
//= require turbolinks
npmパッケージとして利用する場合は、turbolinksモジュールをimport/requireした上でstart()
を実行して開始する。
// 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;
}