LiveConnected (LiveConnected v0.1.0)

Copy Markdown View Source

Defer a LiveView's mount/3 and handle_params/3 until the socket connects.

A LiveView's mount/3 runs twice on first load: once during the static HTTP render (the "dead render", where connected?(socket) == false), and again in the spawned LiveView process once the WebSocket connects. handle_params/3 runs in both phases too. For pages that don't need SSR/SEO, doing the expensive work twice — once for HTML that is about to be thrown away — is wasted effort.

LiveConnected skips the user's mount/handle_params bodies on the dead render and shows a skeleton instead, running the real work only once the socket connects.

Usage

defmodule MyAppWeb.DashboardLive do
  use MyAppWeb, :live_view
  use LiveConnected

  def mount(_params, _session, socket) do
    {:ok, assign(socket, :stats, Analytics.expensive_dashboard())}
  end

  def render(assigns) do
    ~H"<Dashboard.stats stats={@stats} />"
  end

  # optional — omit for a generic skeleton
  def loading(assigns), do: ~H"<Dashboard.skeleton />"
end

Ordering matters

use LiveConnected must come after use MyAppWeb, :live_view. That ordering ensures the ~H sigil and LiveView's callback defaults are in scope when the wrappers are compiled.

How it works

On the dead render the mount wrapper assigns live_connected?: false and returns immediately without calling your mount. The handle_params and render wrappers read that flag: handle_params no-ops, and render calls loading/1 instead of your render/1. On connect the wrapper assigns live_connected?: true and calls super, so everything runs normally.

All phase state keys off the single :live_connected? assign. The handle_params and render wrappers read it defensively (Map.get(..., :live_connected?, true)), so a missing flag fails toward "run normally" rather than crashing.

Opting out

Pass enabled: false to behave like a normal LiveView (runs everything in both phases). This is the escape hatch for when a page later needs SSR/SEO.

use LiveConnected, enabled: false

Caveats

Deferring handle_params moves status codes and redirects to the connected phase. A "resource missing → 404" or an ownership redirect now happens on connect, so the static response is a 200 with a skeleton and the user sees a brief flash of skeleton before the bounce. For the SEO-irrelevant pages this targets that is acceptable. When you need a correct dead-render status, use the cheap-guard pattern: branch on @live_connected? inside your own callback and run a trivial existence/authz check in both phases, deferring only the expensive load. See the README for an example.

Summary

Functions

Injects the deferral wrappers into the calling LiveView.

Functions

__using__(opts)

(macro)

Injects the deferral wrappers into the calling LiveView.

Accepts :enabled (default true). With enabled: false the LiveView runs everything in both phases, like a normal LiveView.