Railsにおけるpjax

このPjaxを実現するためのRailsプラグインとしてpjax_railsが作成されている。

フレームワークにとってこのプラグインは、PJAXヘッダの確認、jquery-pjaxのロード周りの整備などを行う。PJAXヘッダは、HTTPヘッダにおけるPJAXヘッダの有無を確認して、一部のHTMLを返すのか、フルセットのHTMLを返すのか、の判断を行う。

pjax特有のものとして、ページ読み込み時のjavascript読み込み(例えばhead内のscriptタグによる)が行われないため、初期化すべき箇所は自分でハンドリングしならない。

また、このプラグインでは、フルセット部分のレイアウトが行われなくなるため、ページに合わせてtitleタグを変更することも自分で行う必要がある。

最近ではRailsよりもWebサーバ側に近いRack側でpjaxに対応するプラグインが登場している。

https://github.com/eval/rack-pjax/

このプラグインは既存のpjax_railsにおいて、タイトルの変更が難しい点を解決している。短いコードでpjaxを実装している。

https://github.com/eval/rack-pjax/blob/master/lib/rack/pjax.rb

HTTPリクエストがあればRailsがフルセットのHTMLをRackに応答する。
PJAXヘッダがHTTPリクエストに存在していたかを確認し、存在していればpjaxとして扱う。その応答をHTMLパーサ(Hpricot)にてパースし、data-pjax-container属性のあるタグとtitleタグを抜き出して、ブラウザに応答する。抜き出して送信するため、送信サイズは小さくなる。PJAXヘッダが存在していなければ、そのまま返す。

Hpricotによるパーサの影響のためか、aタグの下にdivタグなどを置くと、変なことになる(そもそも置いてはいけない)。

サーバ側の処理を少なくするという利点を殺しているが、レンダリングはpjax_railsよりも意図したとおりに行われるので、手間はこちらの方が少ない。

斜め上、jQuery Mobile

また、別のものとして、jQuery Mobileが存在する。

jQuery MobileもAjaxによるページ遷移を行うが、これはHTMLの抜き出しを必要とせずに、常にフルセットのHTMLを読み込む。フルセットのHTMLの中から、jQuery Mobileが必要とする部分をクライアントのブラウザ上のjsにて判断し、抜き出して表示する。

jQuery Mobileのための独特な属性をHTML上に書く必要がある。

フルセットのHTMLを受信するため、サーバ側の送信データサイズは小さくならないが、画面遷移のための対応をサーバ上アプリケーションでする必要がない、という利点がある。ajaxによるページ遷移の利点のうち、js再ロードとレンダリングが入らないので、これもそれなりに使える。

が、ページ遷移時のscript問題はそのままなので、例えばgoogle analysisなどは独自に対応する必要がある。

ちなみにjQuery Mobileはαの時代に触ったきりなので、リリース後のことはしらない。

rack-pjaxとjQuery Mobile

rack-pjaxはjQuery Mobile的なフルセットな生成を必要としながらも、サーバ上でパーサーを働かせて抜き出してサイズを小さくしてくれる的なもの、に見える。つまり、サーバ側でパースするのか、ブラウザ側でパースするのか、の違い、ということだ。

まとめ

で、いろいろ、あれだけれども、rack-pjaxはそれなりに気に入っているのです。

  • 2つのプラグイン
  • pjax_rails
    • Railsプラグイン
    • レンダリングは必要な部分のみ(layoutは除く)
      • なのでサーバ側は余計な処理(layoutのview処理)をしないから、早くなるはず
      • 出力結果も代わるので注意が必要
    • dhh
  • rack-pjax
    • Rackプラグイン
    • レンダリングはフルセット(layoutも含む)
      • なのでサーバ側は特に変わらない
      • 出力結果も変わらないので処理しやすい
      • Rackでパースして必要な部分だけ送ってくれるので送信サイズは小さい
  • 番外,jQuery Mobile
    • Javascript。普通のHTMLでもscriptタグ書けば対応できる。
    • レンダリングはフルセット(layoutも含む)
      • なのでサーバ側は特に変わらない
      • 出力結果も変わらないので処理しやすい
      • ブラウザでパースして必要な部分だけ使う
プラグイン サーバ処理 データ送信量 ブラウザ側処理 手間
pjax_rails -layout部分view 大(layoutしない部分の対応)
rack-pjax +HTMLパース 小(pjax独特の初期化)
jQuery Mobile 普通 普通 中(独自タグ習得)

実際にこの手のサイトを作ったことがないので、どうとは言えないのだけれども、pjaxやり始めならrack-pjaxあたりで良いと思う。ソースを見ても分かるとおり、とても単純なので。慣れてきたらpjax_railsあたりを使うと良いかと。

jQuery Mobileは昔はもっさりしている気がしたのだが、今は知らない。

あれ

  • jsロード時間とレンダリングって、そんなに時間かかったっけ?
  • データ送信量によってデータ受信時間ってそんなに変わるっけ?
  • layout部分の処理ってcacheで救えるんじゃね?

という疑問も出てくるので測定は大事ですね。。

pjaxプラグインの問題点

例えば、この部分をpjaxで変える、と決めたら、そのdivタグにdata-pjax-containerという属性を加える。

 <div data-pjax-container></div>

そこに決めうちされているので、例えば、左右2ペインのページで左右それぞれをpjaxで更新したい場合は独自に作りこむ必要がある。後は変更したい箇所が入れ子になっている場合も。

なので複雑なことをしようとすると、フレームワークのlayoutの部分と密接に関わるプラグインを作っていかないと、面倒なことになりそうな予感がする。サイトの1部分のみを変更していく、という話ならば、そこまで難しくはない。