HTML over WebSockets: real-time SPAs with barely any JavaScript
Sending server-rendered HTML over WebSockets as a way to build real‑time single‑page apps with minimal JavaScript is stirring debate among web developers. Proponents say it simplifies state management, avoids complex client APIs, and can outperform traditional SPAs for many CRUD and internal tools, especially when combined with frameworks like LiveView, Hotwire, htmx, or Datastar. Critics counter that HTTP/2+SSE often achieves similar latency with fewer operational risks, that server‑held session state complicates scalability and caching, and that the industry has repeatedly moved away from tightly coupled server‑side rendering for good reasons.
Overall reaction to HTML over WebSockets
- Many see this as “MPA with extra steps” or reinvention of old patterns (DHTML, WebForms, Meteor, ASP.NET Ajax, JSF Ajax).
- Supporters argue it delivers “90% of SPA benefits with 10% of the code”: real-time updates, no separate JSON API, and server as single source of truth.
- Critics worry about redundancy with plain server-rendered HTML, added infrastructure and failure modes, and corporate firewalls sometimes blocking WebSockets.
Comparisons: WebSockets vs SSE vs HTTP
- Several argue that for most apps SSE +
fetch()is simpler, easier to operate, and good enough for “push-only” real-time updates. - Others counter that latency isn’t equivalent, especially on HTTP/1, and that WebSockets offer guaranteed in-order messages and bidirectional protocols useful for chat, games, and complex event streams.
- SSE limitations noted: text-only, no guaranteed ordering, per-origin connection limits in HTTP/1.
- Discussion touches on HTTP/2/3 multiplexing and QUIC, and some mention WebTransport as a newer, lower-latency option.
Existing frameworks & prior art
- Multiple frameworks cited as already doing “HTML over the wire”: Rails Turbo/Hotwire, Phoenix LiveView, Blazor Server, HTMX, Datastar, Laravel Livewire, Symfony Live Components, Inertia.js.
- Detailed explanation of Turbo frames/streams shows how partial updates and server-initiated broadcasts work with minimal JS.
- Some argue Datastar/HTMX-style SSE + DOM morphing already gives similar benefits without WebSockets.
Architecture, state, and REST
- Debate over whether this approach is “RESTless”: per-connection server state conflicts with REST’s statelessness but simplifies programming for many internal tools.
- Proponents like that all authoritative state stays on the server, avoiding client/server state desync and halving code versus SPAs.
- Skeptics highlight scaling, load balancing, DoS risk, and monitoring complexity for long-lived connections.
Developer experience & UX tradeoffs
- Many appreciate avoiding large JS bundles and build pipelines; others prefer SPA data-as-source-of-truth models (e.g., Vue/React with typed schemas).
- Complaints about DOM replacement side effects (lost focus, scroll jumps); libraries like idiomorph/Datastar aim to mitigate this but add plumbing.
- General sense that this model fits best for admin panels, internal tools, and moderately interactive apps, less so for highly reactive consumer UIs.
Meta: AI-authorship controversy
- A follow-up article in the same “saga” is accused by multiple commenters of being AI-generated; the author pushes back.
- This sparks a side discussion about disclosure norms around generative AI, reader distrust, and the impact on perceived authenticity of technical writing.