6. Turbolinks
2013/10/03 シナジーマーケティング(株) 鈴木 圭
[Rails 4.0] 第6章 Turbolinks
- 6.1. Turbolinks とは
- 6.2. Turbolinks の注意点
- 6.3. Turbolinks におけるイベント
- 6.4. Turbolinks におけるイベントの注意点
- 6.5. 部分的に Turbolinks を無効化する方法
- 6.6. ready をフックする大量のコードがある場合
- 6.7. Turbolinks を使用しない場合の設定
- 6.8. まとめ
6.1. Turbolinks とは
Turbolinks は Asset Pipeline を活用しているアプリケーションにおいて画面遷移を高速化するライブラリです。
一般的にブラウザがページを表示するときには、
- ページ自体の HTML をダウンロードする。
- ページの中で参照されているスタイルシートや Javascript をダウンロードする。
- ページをレンダリングする。
という順番で処理を行います。ページ内でスタイルシートなどの他のリソースを参照している場合は、ブラウザと Web サーバの間で複数の通信が行われます。
スタイルシートや Javascript への参照は <head> 内で行われることが多く、Rails3 で登場した Asset Pipeline はその部分を最適化する手段を提供しました。
Asset Pipeline は複数のスタイルシートや Javascript を一つのファイルにまとめます。ページから参照するスタイルシートや Javascript ファイルは一つだけになるため、ブラウザとサーバ間の通信が抑えられます。
そして Rails4.0 で登場した Turbolinks は、リンクのクリックイベントをフックし、Ajax リクエストに変換します。そしてレスポンス(新しいページの HTML)を受け取ると、現在のページの <title> と <body> を新しい HTML の <title> と <body> に交換します。こうすることで、<head> 内で参照されるスタイルシートや Javascript をブラウザが取得しなおす処理をスキップすることができます。また、History API を用いてコンテンツのキャッシュやブラウザ履歴の操作が行われるため、ブラウザの戻るボタンが押されたときにも違和感無く前のページの内容が復元されます。
注意として、ページごとに参照しているスタイルシートや Javascript が異なる場合、Turbolinks は力を発揮できません。全てのページが Asset Pipeline で一つにまとめられたスタイルシートと Javascript を参照しているという前提があって初めて、「ページの <title> と <body> だけを入れ替える」という大技が可能になります。
6.2. Turbolinks の注意点
Turbolinks の使い方の前に、注意点をまとめます。
- Turbolinks はデフォルトで(プロジェクト生成時点で)有効になっている。
- Turbolinks を導入すると Javascript のイベント発生タイミングが異なる。
Turbolinks は全体に影響を与える大胆な機能を持つものですが、これがプロジェクト生成時点で有効になっています。「知らなくても良い」ではなく「知らないと思わぬところで躓く」と言えます。
その躓くポイントの最たるものが、Javascript のイベント発生タイミングの違いです。通常であればページが読み込まれたタイミングで load イベントが発生しますが、Turbolinks によって画面が切り替わった場合は load イベントは発生しません。jQuery を使用している場合は、ページが読み込まれたときの処理を以下のように記述することが多いと思います。
$(function() { ... Turbolinks によって画面が切り替わった場合には実行されません. });
しかし、Turbolinks によって画面が切り替わった場合には、上記処理は実行されません。
Turbolinks が裏側で <title> と <body> を入れ替えるため、画面が切り替わったタイミングで onload イベントが発生しなくなります。これは自分で書く Javascript コードではもちろんですが、外部の Javascript ライブラリを使用するときに、そのライブラリが onload で処理を行っていないかも注意する必要があります。
以上のように Turbolinks は全体的な通信量の削減を可能とする反面、よく理解した上で使用する必要があります。
6.3. Turbolinks におけるイベント
Turbolinks を使用しているとイベントの発生タイミングに注意が必要であると先述しました。Turbolinks はリンクのクリックを Ajax リクエストに置き換えてページの内容だけを入れ替えます。そのため、jQuery.ready や DOMContentLoaded を使用しても、ページ切り替え時にそのイベントは発生しません。
代わりに、Turbolinks は独自に定義しているイベントを document に対して発生させます。
例えば画面の切り替えが完了したときに処理を行いたい場合は、次のように page:load イベントをフックします。
$(document).bind("page:load", function() { alert("画面が切り替わりました"); });
新しいページが読み込まれる時は、以下の順番でイベントが発生します。
- page:before-change
- リンクがクリックされた直後。このイベントで false を返すと、Turbolinks による処理はキャンセルされ、通常の画面遷移が行われます。 - page:fetch
- 新しいページのリクエストが開始される直前。 - page:receive
- 新しいページをサーバから受信した直後。 - page:change
- ページの内容が新しい内容に置き換えられた直後。 - page:load
- Turbolinks による画面切り替えの一連の処理が完了した直後。
ブラウザの戻るボタンを押したときなど、キャッシュされた内容からページが復元される場合は以下の順番でイベントが発生します。
- page:change
- ページの内容が新しい内容に置き換えられた直後。 - page:restore
- Trubolinks による一連の処理が完了した直後。
これらのイベントをフックすることで、ページ切り替え時の処理を記述することが可能になります。
6.4. Turbolinks におけるイベントの注意点
Turbolinks を使用する場合のイベント発生タイミングに注意が必要であることを説明しましたが、もう一つ注意すべきことがあります。
それは、直接ページにアクセスされた場合やブラウザで再読み込みされた場合には Turbolinks が発動しないということです。その場合は普通にページの読み込みが行われます。つまり、
- Turbolinks で画面が切り替わった場合
- window の load イベントは発生せず、document の page:load イベントなどが発生する。 - Turbolinks で画面が切り替わらなかった場合
- window の load イベントが発生し、document の page:load イベントなどは発生しない。
ということです。Turbolinks が発動するかどうかによって発生するイベントが異なります。
そのため、どちらの場合にも対応するには次のようなコードを書く必要があるでしょう。
// 画面が切り替わった場合に行う処理. var handler = function() { alert("画面が切り替わりました"); } // 普通に画面が読み込まれた場合. $(handler); // Turbolinks によって画面が切り替わった場合. $(document).bind("page:load", handler); // ブラウザの戻るボタンで画面が切り替わった場合にも処理を行いたければ page:restore にも設定する. $(document).bind("page:restore", handler);
6.5. 部分的に Turbolinks を無効化する方法
特定のリンクだけは Turbolinks を無効化したい(通常の画面遷移をしたい)場合もあると思います。その場合は、以下のいずれかの方法をとります。
- <a> 要素に data-no-turbolink 属性を付ける。
- <a> を囲む要素に data-no-turbolink 属性を付ける。
<!-- (1) 特定のリンクのみ Turbolinks を無効化する --> <a href="..." data-no-turbolink>...</a> <!-- (2) 特定の範囲で Turbolinks を無効化する --> <div data-no-turbolink> <a href="...">...</a> </div>
6.6. ready をフックする大量のコードがある場合
ready をフックするコードが大量にある場合、それら全てを page:load や page:fetch をフックするように置き換えることは現実的ではないかもしれません。特にサードパーティの Javascript ライブラリを使用している場合は難しいでしょう。
対応としては、
- 問題のあるページへのリンクに data-no-turbolink を付ける。
- jquery.turbolinks のようなライブラリを検討する。
- Turbolinks 自体を使用しない。
が考えられます。
6.7. Turbolinks を使用しない場合の設定
Turbolinks を使用しない場合は、以下の作業を行います。
- Gemfile から「gem ’turbolinks’」を削除する。
- app/assets/javascripts/application.js から「//= require turbolinks」を削除する。
- app/views/layouts/application.html.erb の javascript_include_tag や stylesheet_link_tag から「"data-turbolinks-track" => true」を削除する。
6.8. まとめ
Turbolinks という新機能をご紹介しました。非常に大胆な動きをすることに驚かれたかもしれません。
全体的に Turbolinks を使う上での注意点を多く書きました。開発しているアプリケーションとの相性が悪い場合は、Turbolinks 自体を無効化するという判断が必要になることもあるでしょう。しかし、うまく嵌れば大きな効果を生み出してくれる可能性を秘めた新機能ですので、その性質を理解した上で活用したいものです。
次回は StrongParameters について解説します。