もともとRuby on Railsの一部だったturbolinksですが、Rails5からはturbolinksは独立し、Rails以外のプロジェクトでも使えるようになりました。そこで、静的サイトでも使ってみることにしました。かなり体感速度が上がったので、オススメです。
turbolinksとは?
turbolinksとは、ページの移動をすることなく、body
内のデータの入れ替えと、head
内のデータのマージを行うことで、表示を高速化するライブラリです。
ページの移動をしないため、新たにJSファイルやCSSファイルのダウンロードやキャッシュの確認もすることがなく、かなり速く感じます。
turbolinksのメリット
- 表示が速い
- ページがキャッシュされるので一度表示したページは高速に表示される
turbolinksのデメリット
- jQueryのライブラリで動かないものがある可能性がある(
$(document).ready
でのみ評価するものとか) - 戻るボタンで戻ったら動かなくなるものが(略
-
window
,document
オブジェクトは変更されないので、そこを意識する必要がある
とはいえ、対処できないものはあんまりないと思います。
インストール
npm
turbolinksはnpmで提供されているので、導入も簡単です。
$ npm install turbolinks --save
es2015とかで使う場合はrequireしておく必要があります。
const Turbolinks = require("turbolinks");
Turbolinks.start();
jQueryユーザーのためのturbolinks入門
イベントリスナー
$(document).readyイベント
turbolinksを使うと、画面は1度しかロードされないので、$(document).ready
が一度しか実行されません。
そのため、ページを移動するとそれまで存在しなかったDOMに対してのイベント類が設定されません。
turbolinksは独自にイベントリスナーがあるので、それを使います。
$(document).ready
の代わりに、document.addEventListener('turbolinks:load', function(event){});
を使います。
$(document).ready(function() {
$(".foo").on('click', function(event) {
console.log("clicked!");
});
});
document.addEventListener('turbolinks:load', function(event) {
$(".foo").on('click', function(e) {
console.log("clicked!");
});
});
$(window).loadイベント
windowオブジェクトも変更されないので、このイベントも1度しか実行されません。
よって、なるべく使わないように変更したほうがいいでしょう。
turbolinksのイベント一覧
loadだけでなく、turbolinksには多くのイベントがあります。
それをうまく使えば、デメリットに書いていた部分はほぼほぼ解消できると思います。
イベント名 | 説明 |
---|---|
turbolinks:click | リンクをクリックしたときのタイミングで実行される |
turbolinks:before-visit | リンク先に移動する前に実行される |
turbolinks:visit | リンク先に移動しようとしたらすぐ実行される |
turbolinks:request-start | ページを取得するためのネットワーク通信を始めるときに実行される。ヘッダにデータを追加する必要があるときなどはここで処理する。戻るボタンだと発火しない(キャッシュしている場合) |
turbolinks:request-end | ネットワーク通信が終了したら実行される。通信エラーなどはここで処理する。戻るボタンだと発火しない(キャッシュしている場合) |
turbolinks:before-cache | ページがキャッシュされる前に実行される。キャッシュされるとDOMは残るけれどイベントが解除されてしまうので、不要なDOMの削除とかはここでしておく |
turbolinks:before-render | ページがレンダリングされる前に実行される |
turbolinks:render | ページがレンダリングされたら実行される。2度呼ばれることがある。キャッシュ表示で1度目。実際にデータを取得して2度目 |
turbolinks:load | ページが表示されたタイミングで1度目が実行される。あとは移動するたびに実行される。戻るボタンで遷移しても実行される |
静的なサイトの場合は
turbolinks:load
turbolinks:before-cache
くらいしか使いませんでした。
JS, CSSの置き場はheadタグ内に
CSSはともかくとして、JSファイルの読み込みはbodyタグを閉じる直前に書くのが一般的になってます。
これは、htmlのレンダリングをJSのダウンロードよりも先に行わせるためのテクニックですが、turbolinksを使う際にはこれではいけません。
<body>
...
<script src="/assets/application.js"></script>
</body>
turbolinksを使う場合、body
タグ内にJSファイルを置くと、毎回ダウンロード・実行されてしまい、高速化どころか遅くなりますし、挙動がおかしくなります。
head
内に移動させましょう。
<head>
<script src="/assets/application.js"></script>
</head>
<body>
...
</body>
windowオブジェクトへのイベント定義について
turbolinksを使うと、window
, document
オブジェクトは変更されません。
そのため、これらのオブジェクトに対してturbolinks:load
のタイミングでイベント設定をしていたら、ページを移動するたびにイベントを設定してしまうことになります。
// 基本的に1度しか実行されなかったのでこれでもよかった
$(document).ready(function(){
$(window).scroll(function(e) {
// スクロールしたら何かやる
console.log("scroll");
});
});
// ページ遷移する度にwindowに対してイベントが設定されるので絶対にダメ
document.addEventListener('turbolinks:load', function(event) {
$(window).scroll(function(e) {
// スクロールしたら何かやる
console.log("scroll");
});
});
これはそもそも、$(document).ready
のタイミングで定義する必要のないものなので、イベントリスナーの中で定義するのをやめましょう。
$(window).scroll(function(e) {
// スクロールしたら何かやる
console.log("scroll");
});
document.addEventListener('turbolinks:load', function(event) {
// 他の処理
});
$(document).on も同様
実は$(document).on
の定義も、$(document).ready
の中でする必要はありませんでした。なので、これらも外に出します。
// 動的に追加する要素に対してのイベント設定はturbolinks:loadで設定しない
$(document).on('click', '.item', function(event) {
console.log("item clicked!")
});
document.addEventListener('turbolinks:load', function(event) {
$(".foo").on('click', function(event) {
// turbolinks:loadで設定するのは静的な要素に対してのみ
console.log("foo clicked!");
});
});
まとめ
静的なサイトに関していえば、これくらいで十分でした。
また何かTipsがあったら追加していきます。