Elixir Phoenix LiveView: o modelo que elimina o frontend separado
1. Fundamentos do LiveView e o paradigma server-side
Phoenix LiveView representa uma ruptura radical com o modelo tradicional de desenvolvimento web. Enquanto frameworks como React, Vue e Angular transferem a lógica de renderização para o navegador, o LiveView mantém todo o estado da interface no servidor e envia apenas as diferenças visuais via WebSocket. Isso significa que o desenvolvedor escreve código Elixir puro — sem JavaScript para gerenciar estado, sem chamadas AJAX, sem uma API separada.
O segredo está na Máquina Virtual da Erlang (BEAM) e no modelo de concorrência da OTP. Cada LiveView é um processo GenServer independente, capaz de gerenciar seu próprio estado sem bloqueios. Quando 10 mil usuários acessam um dashboard, cada um tem seu processo isolado, e o Elixir gerencia essa concorrência com eficiência impressionante — algo que linguagens como JavaScript ou Python teriam dificuldade em replicar.
# Exemplo: estrutura mínima de um LiveView
defmodule MyAppWeb.CounterLive do
use Phoenix.LiveView
def mount(_params, _session, socket) do
{:ok, assign(socket, count: 0)}
end
def render(assigns) do
~H"""
<div>
<h1>Contador: <%= @count %></h1>
<button phx-click="increment">+1</button>
</div>
"""
end
def handle_event("increment", _value, socket) do
{:noreply, update(socket, :count, &(&1 + 1))}
end
end
2. Arquitetura de comunicação: WebSocket vs REST
Diferente das SPAs tradicionais, onde cada interação exige uma requisição HTTP completa, o LiveView estabelece uma conexão WebSocket persistente. Quando o usuário clica em um botão, o evento viaja pelo WebSocket, o servidor processa a lógica e devolve apenas as alterações no DOM — não a página inteira, nem um JSON completo.
# Comparação de payloads
# SPA tradicional (REST):
# POST /api/counter/increment
# Response: {"count": 1} (30 bytes)
# Cliente atualiza DOM manualmente
# LiveView (WebSocket):
# Evento: "increment" (1 byte)
# Servidor envia diff: {0: ["replace", "span", "1"]} (30 bytes)
# Cliente aplica diff automaticamente
O resultado é uma eficiência de rede drástica. Em aplicações de tempo real — chats, notificações, dashboards financeiros — o LiveView transmite apenas bytes mínimos, enquanto uma SPA precisaria de polling constante ou WebSockets gerenciados manualmente.
3. Eliminando o frontend separado: implicações práticas
A ausência de um frontend separado elimina camadas inteiras de complexidade. Não há API REST ou GraphQL para manter, não há contratos entre backend e frontend, não há problemas de versionamento de endpoints. O estado vive em um único lugar: o servidor.
# Sem LiveView: duas bases de código
# backend/ (Elixir) -> API -> frontend/ (React)
# - Validações duplicadas
# - Tipos inconsistentes
# - Duas equipes
# Com LiveView: uma base de código
# app/ (Elixir) -> WebSocket -> navegador
# - Validação única no servidor
# - Estado centralizado
# - Uma equipe
Para equipes pequenas ou startups, isso significa produtividade multiplicada. Um desenvolvedor Elixir pode construir uma aplicação completa — da autenticação ao dashboard em tempo real — sem precisar dominar React, gerenciamento de estado, TypeScript, ferramentas de build e deploy de frontend.
4. Padrões de desenvolvimento no LiveView
O ciclo de vida de um LiveView segue três funções principais: mount/3, handle_event/3 e handle_info/3. O mount inicializa o estado, handle_event processa interações do usuário e handle_info recebe mensagens de outros processos — como um GenServer enviando dados atualizados.
defmodule MyAppWeb.ChatLive do
use Phoenix.LiveView
def mount(_params, _session, socket) do
# Subscreve ao tópico do chat
Phoenix.PubSub.subscribe(MyApp.PubSub, "chat:geral")
{:ok, assign(socket, messages: [], input: "")}
end
def handle_event("send", %{"message" => msg}, socket) do
# Publica a mensagem para todos os usuários
Phoenix.PubSub.broadcast(MyApp.PubSub, "chat:geral", {:new_msg, msg})
{:noreply, assign(socket, input: "")}
end
def handle_info({:new_msg, msg}, socket) do
# Atualiza a lista de mensagens reativamente
{:noreply, update(socket, :messages, &([msg | &1]))}
end
def render(assigns) do
~H"""
<div id="chat">
<div id="messages" phx-update="append">
<div :for={msg <- @messages}><%= msg %></div>
</div>
<form phx-submit="send">
<input type="text" phx-value="message" value={@input} />
<button>Enviar</button>
</form>
</div>
"""
end
end
A componenteização com Phoenix.Component permite criar blocos reutilizáveis, com slots funcionais e atributos tipados — similar a props em React, mas sem a complexidade de hooks ou efeitos colaterais.
5. Desafios e limitações do modelo sem frontend
Nem tudo são flores. O LiveView depende de uma conexão WebSocket estável. Em redes móveis instáveis ou com alta latência, a experiência degrada rapidamente — cada clique precisa viajar ida e volta ao servidor. Para interações que exigem resposta instantânea (como animações de arrastar ou jogos com física), o atraso de rede torna-se inaceitável.
# Fallback necessário para animações complexas
# Em casos extremos, usa-se Hooks JavaScript:
def render(assigns) do
~H"""
<canvas id="game-canvas" phx-hook="GameHook" />
"""
end
# E no JavaScript:
# let GameHook = {
# mounted() { /* lógica de animação local */ }
# }
Aplicações offline-first, editores de imagem ou ferramentas que precisam funcionar sem conexão contínua são casos onde o LiveView é inadequado. O modelo exige que o servidor esteja sempre presente.
6. Casos de uso ideais e comparação com alternativas
O LiveView brilha em aplicações com forte necessidade de tempo real: chats corporativos, dashboards de monitoramento, painéis administrativos, jogos multiplayer simples, ferramentas de colaboração. Para esses cenários, a produtividade supera em muito o modelo SPA.
# Comparação de complexidade para um chat simples
# React + Node.js:
# - Setup: Create React App + Express + Socket.io + Redux
# - Arquivos: 12+ (componentes, reducer, actions, server, routes)
# - Conhecimento: JSX, hooks, middleware, WebSocket manual
# Phoenix LiveView:
# - Setup: mix phx.new app
# - Arquivos: 3 (live, template, router)
# - Conhecimento: Elixir, LiveView, PubSub
Para projetos com equipe pequena ou foco em backend, o LiveView reduz o tempo de desenvolvimento pela metade. Já para apps com UI nativa (React Native, Flutter) ou requisitos offline, frameworks JavaScript tradicionais continuam sendo a escolha certa.
7. Futuro e ecossistema: LiveView além do básico
Com o Phoenix LiveView 1.0+ estabilizado, o ecossistema se expande rapidamente. Hooks JavaScript permitem interop com bibliotecas do frontend, enquanto ferramentas como Surface UI oferecem componentes prontos com estilos e acessibilidade. O LiveSvelte combina a reatividade do Svelte com a lógica server-side do LiveView, e o Petal Framework entrega um kit completo com Tailwind CSS e Alpine.js.
A tendência de server-driven UI — onde o servidor decide como a interface deve se comportar — está convergindo frontend e backend em uma única stack. O LiveView é a expressão mais madura dessa filosofia no ecossistema Elixir, e seu futuro aponta para interfaces cada vez mais ricas sem a necessidade de escrever JavaScript.
Referências
- Documentação oficial do Phoenix LiveView — Guia completo da API, tutoriais de instalação e exemplos de código
- Phoenix LiveView: A Guide to Real-Time Web Development — Curso prático do Pragmatic Studio com projetos reais
- Elixir School: LiveView — Tutorial gratuito cobrindo desde o básico até padrões avançados
- Building a Real-Time Chat with Phoenix LiveView — Post oficial do blog Phoenix mostrando implementação passo a passo
- LiveView vs React: A Comparative Analysis — Análise técnica comparando desempenho, produtividade e casos de uso
- Surface UI: Component Library for LiveView — Biblioteca de componentes reutilizáveis com slots e estilos pré-definidos
- Petal Framework: The Full-Stack Phoenix Framework — Stack completo com LiveView, Tailwind CSS, Alpine.js e componentes prontos