← Усі статті

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 — коли потрібен постійний двосторонній канал. Архітектура важливіша за моду на конкретну бібліотеку.