JavaScriptを書かずにリアルタイムWeb (Phoenix Framework & LiveView)


PhoenixFramework が JavaScript のコードを書かずに RealTime Web を実装できる LiveView をリリースしたので、2つアプリケーションを作ってみた。

LiveView とは何なのか?

あたりを見るとよく分かる。

特に新しい技術が使われているわけではないのだが、コンセプトがとても面白い。通信には WebSocket が使われていて、 HTML はサーバ側で生成されクライアント側では JavaScript で要素の置き換え程度をしている。これだけ聞くと Turbolinks のようだが、そうではない。

仕組み

通信されるデータとしては、初回はテンプレートと変数一式をクライアントサイドに送り、2回目移行は変わった変数だけを送る。

もう少し具体的には、サーバ側ではElixir のテンプレート(eex等)を変数の箇所で split し、変数の位置を記憶しておく。クライアント側では、split されたテンプレート文字列と変数の List を単純に join して HTML を組み立てる。2回目移行は変わった変数部分を置き換えて、再度 join すれば良い。

つまり、こういうことだ。(本質的な部分のみを簡易化して説明する)

下記のようなテンプレートがあるとする。 @title, @content が変数で、その他の部分は毎回固定文字列となる。

<h1><%= @title %></h1>
<p><%= @content %></p>

初回(mount時)

変数の箇所で split すると、固定文字列は下記のように分割できる。

[
  "<h1>",
  "</h1>\n<p>",
  "</p>"
]

変数の位置は、1個目と2個目の間に @title, 2個目と3個目の間に @content となる。

初回は細切れのHTMLテンプレート文字列全てと、2つの変数を送る。

テンプレ文字列の間に変数を挟むと下記の配列を得る。

["<h1>", @title, "</h1>\n<p>", @content, "</p>"]

あとは単純に文字列として join すれば良い。 @title が “タイトル”, @content が “本文” だったとすると、

["<h1>", "タイトル", "</h1>\n<p>", "本文", "</p>"]
|> Enum.join()
=>
<h1>タイトル</h1>
<p>本文</p>

となる。実際の WebSocket 通信の中身はこんな感じ。

ここまでは特に変わったことはない。

2回目以降

では、@title が “すごいタイトル” に変わったとする。この変更をフロント側で描画したい。全ての値は PhoenixFramework が持つコネクションごとの socket.assigns という場所に格納されている。サーバ側で socket.assigns に新しい値を代入すると、WebSocket がその値をフロントへ運ぶ。

テンプレート文字列は不変なのだから、再度送る必要はない。送れば良いのは変数部分だけだ。1個目と2個目のチャンクの間(0番目)に入る新しい値を送れば十分である。

{ 0: "すごいタイトル" }

@title が “すごいタイトル” になったが、フロント側では特にそんなことは関係なく、先ほどの最初の変数位置の値を “すごいタイトル” に変更し。再度 join すれば良い。

["<h1>", "すごいタイトル", "</h1>\n<p>", "本文", "</p>"]
|> Enum.join()
=>
<h1>すごいタイトル</h1>
<p>本文</p>

とても効率的である。 WebSocket 自体がオーバーヘッドがとても少ないのだが、実データもかなり小さい。

実際の通信はこんな感じ。

もちろん、テンプレート内に配列や if 等があっても問題ない。通信されるデータがややこしくなるが、読めば何となくどういうことをしているのか分かる。実装にあたって、特に中身を気にする必要はない。

作ってみた

2つアプリケーションを作ってみた。Phoenixフレームワークに慣れていれば、8割くらいは迷うことなく書ける印象。画面をまたぐときに結構考える事が多かった。

使用感など

  • テンプレートは今までのものがそのまま使える。つまり、辞めたくなってもコードが無駄にならず通常遷移に切り替えられる。
  • 環境構築が非常に楽で、JS側の環境維持から開放されるのが良さそう。
  • JavaScript を書くことももちろん出来る。Elixir から JavaScript をフックする事もできる。実際のアプリケーションを作るならある程度はJavaScriptを書いたほうが楽なはずだ。
  • JavaScript が無効な環境でも表示はできる(検索エンジンからのリクエスト)

テンプレートが通常の画面遷移で作ったときと同じで動くのがかなり良い。このおかげで、既存アプリケーションを LiveView 化するのも、LiveView を通常遷移に移行するのも、そこまで大変ではないはず。

使いたい部分だけに使えばよいので、あまりデメリットはなさそう。すごく大変になったらベーシックな作りに切り替えれば良い。また基本が websocket channel に載っているため、ネイティブアプリと WebSocket で連携する拡張をしようとしても、おそらくそこまで大変な思いをせずに拡張できそうだなと思った。

コメントを残す

メールアドレスが公開されることはありません。