2012-01-28
pjaxというもの
pjaxというものの話題を目にしたのは昨年だった。
javascriptを用いて動的なページ変化を作ろうと流行ったのはajaxだった。そこにpushStateを用いた履歴管理を含むpjax(pushState + Ajax)なるものが登場した。
Ajaxによるページ遷移はそうではないものに比べて、jsファイルの再ロードや冗長なレンダリングにかかる時間を削減することができる。加えてサーバ側では冗長なHTMLを吐くことを削減できるため、処理時間が短く済む。
通常、Ajaxによる画面遷移では履歴が残らないという問題を持つ。それをpushState関数を使うことで追加できるという。それだけでなく、Ajaxを利用したページ遷移に関連するいくつかの問題も解決している。
Ajaxを用いたページ遷移を行う場合、専用のjsもしくはhtmlの断片を送信することになる。このURLにアクセスした場合、意味を成さない断片をユーザーは手にする。履歴管理をしていても無駄である。この問題の解決にpjaxではHTTPヘッダを用いる。pjaxを利用した画面遷移のURLリクエストに関してはHTTPヘッダにPJAX(HTTP_X_PJAX)を追加する。WebアプリケーションはPJAXヘッダの有無を見ることで、それがpjaxリクエストかどうかを判断し、PJAXリクエストであれば断片となるHTMLを、そうでなければフルセットのHTMLを返信する。
pjaxの最たる例はgithubのレポジトリブラウザとされている。レポジトリブラウザにて何回かの遷移を行った後、アドレスバーに表示されるURLをコピー&ペーストしても、断片ではないフルセットのHTMLが表示される。またレポジトリブラウザの遷移にはアニメーションが用いられるため、フォルダの階層を移動していることが分かりやすい。
Railsにおけるpjax
pjax, Rails, ajax, javascript
この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はそれなりに気に入っているのです。
| プラグイン | サーバ処理 | データ送信量 | ブラウザ側処理 | 手間 |
| pjax_rails | -layout部分view | 小 | 小 | 大(layoutしない部分の対応) |
| rack-pjax | +HTMLパース | 小 | 小 | 小(pjax独特の初期化) |
| jQuery Mobile | 普通 | 普通 | 小 | 中(独自タグ習得) |
実際にこの手のサイトを作ったことがないので、どうとは言えないのだけれども、pjaxやり始めならrack-pjaxあたりで良いと思う。ソースを見ても分かるとおり、とても単純なので。慣れてきたらpjax_railsあたりを使うと良いかと。
jQuery Mobileは昔はもっさりしている気がしたのだが、今は知らない。
あれ
という疑問も出てくるので測定は大事ですね。。
pjaxプラグインの問題点
例えば、この部分をpjaxで変える、と決めたら、そのdivタグにdata-pjax-containerという属性を加える。
<div data-pjax-container></div>
そこに決めうちされているので、例えば、左右2ペインのページで左右それぞれをpjaxで更新したい場合は独自に作りこむ必要がある。後は変更したい箇所が入れ子になっている場合も。
なので複雑なことをしようとすると、フレームワークのlayoutの部分と密接に関わるプラグインを作っていかないと、面倒なことになりそうな予感がする。サイトの1部分のみを変更していく、という話ならば、そこまで難しくはない。