PjaxとSPAの違い

PjaxとSPAが全く同じ技術構成なのを知らずにPjaxを過去の技術だと思ってる知ったかぶりが多いので最も高度で完成度の高いPjaxライブラリであるpjax-apiの作者の自分が説明しておこう。

SPAとはPjaxをバンドルしたフレームワーク

Pjaxとはその語源からしてpushState+Ajaxである。そしてSPAの技術構成はフレームワーク+pushState+Ajaxである。すなわちSPAとは本質的にPjaxをバンドルしたフレームワークに過ぎない(Pjaxと対比されるSPAはツールセットとしてのSPAでありこれはアプリケーションフレームワークとしてしか存在し得ない。字義通りのSPAはSPAフレームワークで作ろうとPjaxで作ろうと何で作ろうとSingle Page ApplicationであればSPAである)。SPAを使っている限りPjaxも使っているのでありPjaxが過去の技術のごとき言説は無知を晒しているだけである。なおウェブ標準的にはAjaxはfetchに置き換えられているがPjaxも内部のAjaxをfetchに置き換えるのに何の支障もないので名前が古いままになるだけである。

実質的差異はデータフォーマットだけ

PjaxはAjaxなどの非同期通信APIによりHTMLを取得しページを更新するがSPAはJSONを取得しページを更新する。PjaxとSPAの共通部分の実質的差異は取得するデータのフォーマットがHTMLかJSONかという非同期通信の運用上の差異しかないのである。そしてその差異もそれぞれの利用方法において効率的なデータフォーマットを選んだ結果でありPjaxはページ遷移時にHTMLを差し替えるのみで足りるのでHTMLを取得しSPAはJavaScript上でDOMを常時状態管理してるのでJavaScript上の状態更新に適したJSONを取得しているに過ぎない。

HTMLとJSONで何が変わるか

データフォーマットをHTMLからJSONに変える主な利益はデータサイズである。HTMLよりもJSONのほうが簡潔で小さい。しかしPjaxでもそのような実装はやろうと思えば当然可能であり設計方針の違いでしかない。それよりもSPAがサーバーサイドの技術選択を制限する不利益のほうが大きい。

クライアントサイドにおいてはJSONを使用するSPAのほうが効率的に見えるがHTMLベースのPjaxでもHTMLリクエスト先のURLをテンプレートに書き換えることでローカルキャッシュを使わせ並行してリクエストした差分JSONとテンプレートを合成したHTMLを使用してページを更新できpjax-apiはこの更新方法をサポートしている。初回ページ遷移時のテンプレートリクエスト分のデータサイズはかかるが数百文字程度しかなく差分データやSPAにより肥大化したHTMLとCSSJavaScriptに比べれば微々たるものである。

サーバーサイドにおいてもSPAは専用のフレームワークやライブラリのサーバー上での使用を要求しこれはほとんどの場合JavaScriptであるためJavaScriptという低速な言語によりサービスのスループットもレイテンシも非常に悪く不経済なものとなる。GoやRustなど他の高速な言語との組み合わせは不可能ではないが一般的とは言い難く自力で解決しなければならない部分が多いだろう。対してPjaxはブラウザ上で完結したライブラリであるためサーバーサイドの制約がなく任意の高速な言語と技術構成でサーバーを構築できる。

SPAとPjaxの開発上の違いはフレームワークとライブラリの違いであり既成品の組み立てキットを組み立てるか自分で図面を引いて部品を作って組み立てるかの違いである。設計能力も実装能力も兼ね備えた優れた開発者にとってフレームワークは耐え難く不自由でライブラリでなければ思い通りのものを作れない。設計能力の欠けた者、セミオーダーの既成品を量産するような仕事をしている者、とにかく早くプロトタイプを作らなければならない者にはフレームワークが適しているが最高の一点物を作るにはライブラリである。さらに必要ならフレームワークもライブラリも自分で作るのが最高峰の世界である。そしてReactもAngularも自社利用のために作られたフレームワークである。アプリケーションフレームワークというものは最高のアプリケーションを作ろうとするとどうしても細部に手が届かずフレームワークごと作り込まなければならなくなるものなのである。ライブラリであれば不足分は基本的に独自アプリケーションの一部として生じるためライブラリに手を加える必要はない。一般的にアプリケーションはフレームワークではフレームの中に作られるのでフレームが妨げになると拡張困難になるがライブラリではライブラリの外に作られるのでライブラリが適さなければ代わりの最小独自実装を内部的に作ればいいだけである。また陳腐化した場合の刷新もライブラリは段階的に行えるがフレームワークは一括して行うしかない。フレームに合わせて作る以外自由がないのがフレームワークである。

将来のPjax

Pjaxを構成するpushStateなどのHistory APIに代わるNavigation APIが現在策定中でありこれが標準化されればPjaxは名称と実装が完全に異なるものとなってしまうがライブラリとしては依然として内部実装を更新するだけで済むことである。機能的にもNavigation APIは基本的に既存APIを使いやすく再構成した便利API集で、現在のSPAとPjaxがすでに特に不足のないサービスを実現しているように基本機能は既存APIで足りている。従来不可能だったことが可能になる部分もあるものの現在特に不便を感じないように実際上ほとんど必要にならないものである。具体的にはリンクなどによるページ遷移の完全な捕捉と、厳密な遷移状態と遷移履歴の提供であるがオーバーエンジニアリングとユーザーの行動追跡が促進されるだけである。そんなことより既存の標準APIを正しく実装しろと言いたい。History APIの一部であるscrollRestoration APIFirefoxではずっと壊れており、Chromeでは正しく動作していたが最近壊れて共に用をなさなくなった。いずれFirefoxが修正すると思って放置してたがまさかChromeが壊してくるとは思わなかった。おかげで諦めて独自のワークアラウンドを実装することになったがこのようにNavigation APIがなくともほとんどのことはできるのである。むしろ単機能のHistory APIすら実装できてないのに遥かに複雑な統合的APIであるNavigation APIを正しく実装できるのか疑問になる。Navigation APIのプロダクションレベルのブラウザ互換が確保されるまで標準化から早くとも5年程度はかかるだろう。ちなみに他のPjaxライブラリを使うのはやめとけどれだけ有名でもクソ実装だ。