Phoenixウェブ・フレームワークが一般公開されてから9年、Phoenix LiveViewは最近1.0(リリース候補)に達した。LiveViewによって、開発者はJavaScriptを書くことなく、リッチでリアルタイムのサーバー・レンダリング・アプリケーションを作成できる。LiveViewはErlang仮想マシン(BEAM)に依存しており、複数のプロセスで同時に処理される何百万ものWebSocket接続に対応できる。
PhoenixフレームワークのプログラマーであるChris McCord氏は、LiveViewがどのようにして生まれたかを次のように説明している。
私は痒いところに手が届くようにLiveViewを始めました。JavaScriptを書かずにダイナミックなサーバー・レンダリング・アプリケーションを作りたかったのです。JavaScriptがもたらす必然的に膨れ上がる複雑さにはうんざりしていました。HTTPグルーやGraphQLスキーマ、リゾルバを書き、どの検証ロジックが共有され、あるいは複製される必要があるかを考えます。ローカライゼーション情報をどうやってクライアントに伝えるのでしょうか?どのようなデータ・シリアライザーが必要なのでしょうか?WebSocketとIPCをどのようにコードに戻すのでしょうか?JSバンドルが大きくなりすぎていないでしょうか?WebpackやParcelのノブを回し始める時だと思います。私たちは皆、この痛みを感じています。
Phoenix LiveViewはPhoenixエコシステムのメンバーであり、プログラマが、フロントエンドの別個のコードベースをほとんどまたはまったく使用せずに、リアクティブなウェブ・アプリケーションを書くことを可能にする。LiveViewはHTTPではなくWebSocketを活用し、クライアントとサーバー間のステートフルで長寿命のコネクションを維持する。ユーザーの操作に応答するウェブページとその更新は、サーバーによって提供される。クライアント/サーバー間のメッセージは、非常にスケーラブルなPhoenixチャンネルを使用する。サーバーは、双方向ソケットチャネルを使用して、他のアプリケーションユーザーからの操作をクライアントに返信できる。
WebSocketは通常、HTTPよりもレイテンシーが低い。持続的な接続により、コネクションを何度も確立する必要がなく、ハンドシェイクやネットワークのオーバーヘッドを最小限に抑えられる。WebSocketは、スピードが重要なリアルタイムのやりとりでは、より効率的であることが多い。しかし、WebSocketは、接続状態を維持するために追加のサーバー・リソースを消費する。
一方、HTTPリクエストは、キャッシング、CDN、ロードバランシングのような分散メカニズムから恩恵を受ける。しかし、HTTPやRESTでステートフルなウェブ・アプリケーションを実装するには、クライアント側でステートを維持する必要がある場合がある。HTTPリクエストでステートの断片を渡すと、ペイロードが重くなり、待ち時間が長くなる。または、サーバーが取得できるように外部の場所にステートの一部を保持する必要がある。このパラダイムでは、ステートレス・サーバーはアプリケーションの状態とは無関係に拡張できる。
Mc Cord氏は、LiveViewのレイテンシの優位性を次のように説明する。
すべてのLiveViewはサーバーとの接続を保持していますので、ページナビゲーションはライブナビゲーションで行われます。TLSハンドシェイク、カレントユーザー認証などは、ユーザーの訪問の間、一度だけ行われます。これにより、1つのWebSocketフレームを介してページナビゲーションが行われ、クライアントのアクションに対するデータベースクエリが少なくなります。その結果、クライアントからのラウンドトリップが減り、サーバーが行う作業も単純に減ります。これにより、SPAがデータをフェッチしたり、突然変異をサーバーに送信したりするのに比べ、エンドユーザーにとって待ち時間が少なくなります。
Mc Cord氏は、サーバーのメモリ負荷にもかかわらず、LiveViewはWhatsAppのような大規模なユーザーベースを持つアプリケーションをカバーするのに十分なスケーラビリティを維持していると主張している。
ステートフルな接続を維持するためには、サーバーのメモリが犠牲になりますが、人々が期待するよりはるかに安いです。ベースラインでは、与えられたチャネル接続は40kbのメモリを消費します。このため、1GBのサーバーの理論的な同時LiveViewの上限は25,000までとなります。もちろん、より多くのステートを保存すればするほど、より多くのメモリーを消費しますが、必要なステートだけを保持すればいいのです。また、メモリに影響を与えずに大きなコレクションを扱うための
stream
プリミティブもあります。ElixirとErlang VMはこのために設計されました。ステートフルなシステムを何百万人もの同時ユーザーにスケールさせるのは、机上の空論ではありません。WhatsApp、Discord、あるいは私たち自身のベンチマークがその例です。
LiveViewは、レイテンシーをさらに改善するために、ネットワーク・ペイロードを最小化するよう努力している。そのために、ユーザーの操作に応じてクライアントに送信する最小限の情報の特定を容易にするページテンプレートの仕組みと、ウェブページ上で実行する後続の最小限の更新を計算するDOM差分ライブラリ(例えば、morphdom)を使用している。Elixirプログラミング言語の開発者であるJosé Valim氏は、LiveViewの最適化に関する技術的な詳細をブログで発表した。
LiveViewにはさらに、HEExと呼ばれる宣言型コンポーネント・システムも含まれている。HEExコンポーネントは、依存関係(例:props、state、slots)がアノテーションされたマークアップ生成関数である。例を以下に示す。
@doc """Renders a button.## Examples <.button>Send!</.button> <.button phx-click="go">Send!</.button>"""attr:type, :string, default: nilattr:rest, :global, include: ~w(disabled form name value)slot:inner_block、 required: truedefbutton(assigns) do ~H""" <button type={@type} class="rounded-lg bg-zinc-900 hover:bg-zinc-700 py-2 px-3 text-white" {@rest} > <%= render_slot(@inner_block) %> </button """end
先ほどのコードでは、カスタム属性(type
)、標準HTML属性(global
)(class
など)、slot引数を1つ受け付けるコンポーネントを紹介した。コンポーネントは関数であるため、テンプレート部分よりも再利用性が高い。コンポーネント・スロットは、ユーザーによるカスタマイズの追加レイヤーを提供する。
あるRedditユーザーは、この新しいリリースについて次のように熱意を語っている。
素晴らしいニュースです!ついにここまで来ました。
本業でもサイドプロジェクトでも毎日Phoenix(LiveViewあり・なし)を使っていますが、これ以上嬉しいことはありません。このスタックを使っていると、とても生産性が上がるのです。他のものを使ってウェブ開発をすると、まるで流砂の中を走っているような気分になります。
Elixirが今後どのように発展していくのか、とても楽しみです。Elixirはまだ比較的小さいですが、大きくなる一方ですし、とても明るい未来が待っていると思います。
LiveViewはサーバー上で動作し、フロントエンドにはコンパニオンJSライブラリーがある。Phoenixウェブアプリで書かなければならないJavaScriptコードの量は大幅に減るが、カスタムJavaScriptを書くことは可能であり、場合によっては必要である。
Phoenix LiveViewは、MITライセンスの下で配布されているオープンソースプロジェクトである。興味のある開発者は、LiveViewのドキュメントを確認できる。