Part 7 · 1 chapters · ~8 min

Phoenix and LiveView Internals

Plug and the connection struct, the endpoint and Cowboy or Bandit HTTP servers, Phoenix.PubSub and its adapters, Channels and the socket protocol, Presence with CRDTs, LiveView's lifecycle (static render, connect, mount, handle_event, handle_info), change tracking and diffs, LiveView JS hooks, and LiveView's trade-offs.

8

Real-time without a SPA

code
defmodule LedgerWeb.BalanceLive do
  use LedgerWeb, :live_view
  def mount(%{"id" => id}, _session, socket) do
    if connected?(socket), do: Phoenix.PubSub.subscribe(Ledger.PubSub, "account:" <> id)
    {:ok, assign(socket, id: id, balance: Ledger.balance(id))}
  end
  def handle_info({:posting_created, %{account_id: id}}, %{assigns: %{id: id}} = socket),
    do: {:noreply, assign(socket, balance: Ledger.balance(id))}
  def render(assigns), do: ~H"""
  <p>Balance: <%= format_ngn(@balance) %></p>
  """
end

Presence tracks who is online across a cluster using a CRDT (Distributed Systems, Formal Theory P6), so it converges without a central store. Bandit, a pure-Elixir HTTP server, is now the default in new Phoenix apps, replacing Cowboy.

HOW LIVEVIEW WORKS
server-rendered, stateful, real-time UI over a WebSocket
browserLiveView processPubSubGET /balance (static HTML first)WebSocket connect; mount/3
swipe the figure sideways, or tap expand for full screen
1/4
first render
The first request returns full HTML (fast first paint, SEO); the client then opens a WebSocket and a LiveView process mounts on the server.
HTML first, then socketone process per page