← Все статьи

HTML поверх WebSockets: SPA почти без JavaScript

Паттерн LiveView: сервер шлёт готовый HTML по постоянному каналу — без отдельного API и тяжёлого фронтенд-фреймворка.

HTML поверх WebSockets: SPA почти без JavaScript
Содержание

Коротко

Классическое одностраничное приложение — это два мира: клиент рисует интерфейс из JSON, сервер отдаёт данные по контракту API. Статья на Andros.dev напоминает про другой путь: HTML поверх WebSockets. Сервер сразу отдаёт собранную разметку, а тонкий клиент только вставляет её в нужное место и слушает события.

Так устроены Phoenix LiveView и родственные решения в Django, Laravel, .NET и других стеках. Речь не про «убить React», а про осознанный выбор транспорта и места, где живёт отрисовка.

Что произошло

Автор разбирает семейство гипермедиа: готовый HTML «по проводу» может ехать по обычному HTTP (htmx, Unicorn), по одностороннему SSE (Datastar) или по двустороннему WebSocket — именно этот вариант и называют паттерном LiveView.

Идея восходит к ElixirConf 2019: Крис Маккорд за четверть часа собрал клон Twitter на Phoenix LiveView без клиентского движка отрисовки. С тех пор похожие библиотеки появились почти в каждом языке. Клиентский JavaScript остаётся, но его роль узкая: открыть канал, разместить HTML, анимации и обработка жестов — без дублирования бизнес-логики на двух языках.

В обычной схеме браузер запрашивает JSON, парсит его и собирает дерево документа. В схеме LiveView по постоянному каналу уходит уже готовый фрагмент: сервер запрашивает данные, рендерит шаблон и может сам рассылать обновления всем подключённым клиентам, не дожидаясь опроса.

Почему это важно

Для многих команд сложность одностраничного приложения — не в «красивых компонентах», а в синхронизации двух кодовых баз и контрактов. Один движок шаблонов на сервере сокращает поверхность ошибок: нет промежуточного GraphQL или REST «ради интерфейса», состояние сессии живёт рядом с данными, чат или живая панель получаются почти без отдельной подсистемы рассылки.

Есть и цена. Сервер держит открытый канал и часто — состояние каждого клиента в памяти; горизонтальное масштабирование требует общего слоя (в экосистеме DjangoChannels, ASGI и Redis). Высокая сетевая задержка бьёт по ощущению мгновенности, офлайн-режим почти невозможен, а кривая входа круче, чем «подключить htmx на кнопке».

Автор честно сравнивает с SSE: если поток в основном от сервера к клиенту (лента, уведомления, поток токенов ответа модели), односторонний канал дешевле в эксплуатации. WebSocket оправдан, когда нужен плотный двусторонний обмен — совместное редактирование, игры, чат.

На практике

  1. Сначала сформулируйте, нужен ли двусторонний обмен в реальном времени или достаточно рассылки с сервера и обычных запросов.
  2. Если выбираете LiveView — держите важный контент в первой серверной отдаче: поисковики не увидят поздние патчи по WebSocket.
  3. Закладывайте переподключение и понятное поведение при обрыве канала — иначе интерфейс развалится при нестабильной сети.
  4. Планируйте память и привязку сессии (или общий слой канала) заранее: пик одновременных подключений — главный риск, а не «протокол сам по себе медленный».
  5. Смотрите зрелость экосистемы: Phoenix LiveView 1.x, Laravel Livewire с Reverb, Blazor Interactive Server, Django LiveView и Reactor — у каждого свой компромисс по зрелости и сопровождению.

Для прототипа на скромном железе автор приводит собственный опыт: сотни одновременных читателей без отдельного фронтенд-монолита. Для корпоративной нагрузки те же принципы, но с явным бюджетом на состояние и отказоустойчивость.

Итог

HTML поверх WebSockets — зрелый способ собрать интерактивное приложение в одном языке, без обязательного тяжёлого клиентского фреймворка. Транспорт выбирают под задачу: HTTP для запрос–ответ, SSE для дешёвой рассылки с сервера, WebSocket — когда нужен постоянный двусторонний канал. Архитектура важнее моды на конкретную библиотеку.