Back to News
Advertisement
Advertisement

⚡ Community Insights

Discussion Sentiment

71% Positive

Analyzed from 2440 words in the discussion.

Trending Topics

#server#web#more#http#html#requests#client#page#websocket#https

Discussion (59 Comments)Read Original on HackerNews

xutopia12 minutes ago
Funny he mentioned Chris McCord as the originator of this technique with Liveview. The reality however predates that with Sync in Rails that you guessed it... was also Chris McCord's doing. Rails at the time didn't have the capacity to handle it so it was just a tech demo then and a big reason why Chris McCord moved to Phoenix. He was once a prolific Rails developer. That guy is helping the web move forward.
hackingonemptyabout 3 hours ago
> The quick rule: if you need bidirectional, low-latency communication (chat, collaboration, games), WebSocket; if you only push from the server, SSE is simpler and cheaper to operate.

For most apps just use SSE and the built-in code for making HTTP requests (Fetch) instead of hacking up your own client side JS to make requests over a WebSocket. The latency is the same because modern browsers multiplex HTTP requests over a single TCP connection that is left open.

Maybe if you are making many client requests per second there is an advantage to not sending full headers/cookies/etc... on each request but not if you're sending requests in response to user clicks/touches.

Any sufficiently complicated SPA contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Fetch.

clappskiabout 3 hours ago
> The latency is the same because modern browsers multiplex HTTP requests over a single TCP connection that is left open.

In my experience this isn’t true; firstly you’re relying on an implementation detail of the platform that you’re executing on, of which you have no control over on the client side. Secondly, even if you aren’t opening a new connection per request, you’re still travelling through an entire HTTP stack implementation rather than the incredibly simple WebSocket protocol - effectively a length and a mask to get the contents, rather than some (in http1 land) fuzzy parser.

If you can guarantee you’re hitting http2 or http3 then you might be closer in latency, but due to the complexity of both I would imagine plain http1 negotiated persistent WebSockets provide the best latency.

galaxyLogic18 minutes ago
But, if you can do things on the client (with JavaScript) you don't need to send (so many) requests to the server, making latency less of an issue.

Doing things on the client means user's CPU is doing some work which else would need to be done on the server, for maybe thousands of clients at the same time.

So I understand some people don't like JavaScript, but then I think the solution would be WebAssembly. I mean the point of distributed computting is that the computational load can be distributed. Perhaps counter-intuitively that often also means less need fo communications and latencies.

jallmann22 minutes ago
Sure, but SSE connections in the browser - the typical use case - are persistent, so there shouldn't be frequent re-connecting.

Unlike WebSockets, browser SSE also has a built-in recovery mechanism so you don't miss events across reconnects (`Last-Event-ID` header), although this does require explicit support from the server-side app.

Given that the WebSocket handshake has an additional round-trip, SSE would typically be faster in terms of time-to-first-byte.

> you’re still travelling through an entire HTTP stack implementation rather than the incredibly simple WebSocket protocol

Both protocols have their own minimal framing, but "an entire HTTP stack" is a stretch. It's hard to argue that `data:value\n\n` is more complex than the WebSocket binary protocol. Simplistic, sure (no binary payloads), but also simple enough to, say, pipe through a regex. Good luck doing that with WebSocket.

simlevesque17 minutes ago
No mention of WebTransport makes me very doubtful of this article. It's 2026, all browsers support it and it's bidirectional and lower-latency than WebSocket.
sublinearabout 3 hours ago
> Any sufficiently complicated SPA contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Fetch.

Sound advice otherwise, but you could have left this part out of the comment :D

You underestimate how many "sufficiently complicated SPAs" are slapped together low-code projects. Their maintainers have no idea what you're even talking about.

hackingonemptyabout 1 hour ago
You're right and said maintainers probably have never heard of Greenspun's Tenth Rule either.

https://en.wikipedia.org/wiki/Greenspun's_tenth_rule

sam_lowry_about 1 hour ago
Argh... you did not get the joke.

Here is the original: https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule

nchmyabout 3 hours ago
A good response to this post

https://yagni.club/3mstlyuxe5s26

andros36 minutes ago
tommica11 minutes ago
Love the nuance that is going on. Absolute blast to read posts by people that truly understand the technogy they are working with.
sudodevnull8 minutes ago
ai slop
chrisweeklyabout 3 hours ago
Excellent article. More compelling than TFA being discussed. Thanks for sharing!
pseudosavantabout 3 hours ago
Definitely a well reasoned counter point to choosing websockets over SSE.
nchmyabout 3 hours ago
I forgot to link to OP's response to the response. It's mostly Ai slop.

https://en.andros.dev/blog/bd74e61a/were-fighting-over-the-w...

cmoskiabout 1 hour ago
It's a better argument than the Datastar supporter's.
whitemoonxabout 2 hours ago
God damn
isomorphic-15 minutes ago
Allowing unmoderated real-time chat with all visitors is certainly a decision.
deepsunabout 2 hours ago
> Place the HTML where it belongs

Well, some drawbacks are not accounted for when replacing HTML parts: input elements lose focus, if some view was scrolled, then it gets unscrolled, jumping under user's pointer etc.

sudodevnull7 minutes ago
things like datastar handle this automatically for you
cmoskiabout 1 hour ago
I don't recall encountering these issues. What framework was that on?
deepsun7 minutes ago
Any framework, if you _replace_ DOM elements, not just modify their attributes.
nzoschkeabout 2 hours ago
Close but htmx with SSE and dom swaps and morphing gets you there without reinventing any wheels.

Pretty much every web app I build has this pattern in it from day 1, as they all quickly expand to have a realtime inbox and notifications subsystem to support workflows and agents.

nchmy8 minutes ago
now check out datastar for a smaller, faster, more extensible, more powerful version of that
aitchnyuabout 2 hours ago
I like the Vue/React/Svelte model of the DOM being a function of the data. For example, in a shopping cart, I add two chocolates, the number against the chocolate, the count at top and a banner encouraging me to reach X total all center around a data structure.

I use Django Ninja, Zod, InertiaJS+Vue and its as easy as using Django's templating engine, but static typing ensures my view doesnt emit unrepresentable data, my TS doesnt accept unrepresentable data, Vue+TS dont allow logic errors in template. AI makes it effortless. Again, the loaded page is a function of the data supplied at the view.

With HTMX, I'm writing several server-side functions to mutate the DOM imperatively and using HTML attributes to call them. Its great for forms but that shopping cart example needs code scattered across multiple functions and templates.

MrBuddyCasino30 minutes ago
Yes I don’t see the appeal of HTMX in most cases. Vuejs has less footguns than React, and LLMs can produce it decently well to at least get started and then refactor.
llbbdd20 minutes ago
The appeal is that it's not React, aimed mostly st people who have a grievance against React for one ill-informed reason or another. In time it will either become React by another name or die out.
pjmlpabout 3 hours ago
Love how DHTML, ASP.NET Ajax, JSF Ajax kind of keeps being re-invented.
tclancyabout 2 hours ago
Indeed, “The initial learning curve is steeper than dropping in a <script>”. Maybe for you, but I was doing that basic thing in a mix of Django around 2010. It was getting away from traditional form POST and reload the page while still taking advantage of Django’s templating system. I keep trying to find the best answer to this approach across the things available as it feels like it would make vibe coding easier to manage and understand as well.
noopydoopyabout 2 hours ago
Exactly dear Lord we went the spa route for a reason
pjmlpabout 2 hours ago
The problem is that we went too far, and newer generations are now rediscovering the past.
altairprimeabout 1 hour ago
> that loose back-and-forth over HTTP weighs more than an always-open WebSocket

This is definitely true for HTTP/0 and /1. Is it still true under HTTP/3, or has the underlying ‘single conduit, many channels’ model improved things if used correctly?

carllercheabout 1 hour ago
Topcoat (Rust) is aiming taking this approach as well: https://github.com/tokio-rs/topcoat. The project is still in the early days. It won't require WebSockets, but WebSockets will be an option.
austin-cheneyabout 2 hours ago
HTTP over WebSockets: Sounds like the same tag line I have been using in my project for the past 2 years.

https://github.com/prettydiff/aphorio

My approach is pretty simple. Since the connection phase of WebSockets is RFC2616 compatible, per RFC6455, you can use the same server logic to connect both.

Advertisement
mattrighettiabout 2 hours ago
> Less traffic and less latency per action: a single persistent connection avoids repeating the TCP handshake and the HTTP headers on every interaction.

You don’t need a TCP connection for everything.

If you’re optimizing for that you can consider client-side caching which you can instruct using cache headers that every browser support. That usually reduces heavy hitters by a lot, even if you set the browser TTL to 1 minute which is fine for most of the scenarios.

conradfrabout 2 hours ago
Just wanted to mention that in PHP besides Laravel Livewire there's also Symfony Live Components[0]

[0] https://symfony.com/bundles/ux-live-component/current/index....

floodfxabout 2 hours ago
A few years back I wrote a backend implementation of the LiveView protocol in Typescript (https://liveviewjs.com) and played around with another BunJS-specific implementation (https://hotdogjs.com/). (Also did Java and Go versions but that's another story.)

There isn't an official "protocol" so I had to figure it out by watching the WS traffic and determining how it worked which was fun if not tedious. That said, the more I learned, the more I was impressed by the efficiency and the programming model which felt simpler yet more powerful than SPAs.

I did get to a point where I just got too busy to keep up and over the last couple of years things have changed a bit on the "protocol" side.

But recently (a week ago-ish), I started poking at the old LiveViewJS repo with the help of coding agents. Now that Phoenix is past 1.0 and the JS runtimes (Node, Deno, Bun) have more overlap in terms of APIs and library support, I think it will be more straight forward and frankly easier to get and stay at parity.

egeozcanabout 2 hours ago
This gives me too much <script runat="server"> or even JSF vibes.
noopydoopyabout 2 hours ago
They keep trying to reinvent webforms, bleh
mircerlancerousabout 1 hour ago
Frankly I think serving dynamic HTML at all is a problem in an SPA. Use a service worker to cache structure, control, and styling, then use an API to fetch dynamic data in a more efficient manner.
hyperhelloabout 3 hours ago
What’s wrong with this idea, really? It’s redundant because you can serve HTML to requests with Apache or Ngnix or any other server on the happy path.

What’s right with the idea, really? It’s exactly what the tried and true preferences of developers have been shown to be: getting in the way of the happy path for no reason.

Now you can have build steps and put story points in Jira and do it all on the server where we don’t have to see it, and the success condition is that the text gets served. Both sides can be happy now.

doublerabbitabout 3 hours ago
> What’s wrong with this idea, really? It’s redundant because you can serve HTML to requests with Apache or Ngnix or any other server on the happy path.

Overhead, Security, Denial of service to name a few.

You now have two states to track. Is the web-server serving the current version that the web socket is rendering?

Is your monitoring enough? Is your monitoring going to detect if the web-socket server is suddenly taken offline? How do you monitor your web server is alive and ready to serve requests in the time of need?

How do you determine if the socket server is actual offline and not frazzled itself in an event-loop? A stray network packet you never conditioned it for.

If both your web-socket server and the web-server are going to follow the same source of truth for fail-over why not just use the web-server?

The web-server is a tried and true method of serving websites. An application that allows you to easily load balance; tune and enhance with other security features. The best part is than you can actually serve a website without requiring JavaScript.

Enterprise/corporate/country DPI firewalls like to silently block web sockets; any requests you're going to be rendering blank back to the client. Determining if the client is blocked isn't easy and how do you let the clients report an issue if they can't render the support page?

The starting sequence of a web socket is an HTTP request header to an upgrade the connection. Correctly configured DPI firewalls block these upgrade headers so for all you know the connection has been made but the renderer fails silently.

You still need a service to serve the JavaScript fronted so unless you create a WebSocket HTTP server which you've then opened a can of worms; you have a perfectly functional web-server sitting around idly wasting resources.

As I bombard your web-socket server with faux requests slowloris style. Your web-server is alive and as far as it knows your socket server is alive too, how do you determine if the web socket is actually under attack? This adds more complexity in the mix.

It's not wrong per-se. For a infrastructure learning exercise sure. However for anything else it's a waste of time and will cause headaches. The resources and the overhead for it all just isn't worth it. It's a mirage of something that looks opportunistic but isn't.

Furthermore any alterations need testing on both parts. If you were to apply a hotfix for the web-socket side, does this negatively effect the web-server side?

Does it perform the same way in Firefox and Chrome? If Firefox is slower at parsing the JavaScript html json, how are you going to accommodate that?

frollogastonabout 2 hours ago
Article should've mentioned caching, or lack thereof
doublerabbitabout 3 hours ago
> Simple, elegant and fast.

Until someone bombs your websocket server and you then have nothing at all.

ChiperSoftabout 4 hours ago
Is this satire? Rage bait? Why would you ever do this?

Just make a normal website!! You've invented an MPA with extra steps!

x0x0about 3 hours ago
Responsive site built via server-side render, with a particular benefit for partial page updates. 90% of the benefit of an SPA but 10% of the code: no api, no moving of system of record for state back and forth between database and browser (it's always db), etc. And you can avoid react.

A common use case: eg in Rails, a user has a table open. you can stream new records to the top of that table as they are created in ~5 lines of ruby (a broadcast on the model, and put the table rows in a turbo_frame with a turbo_stream_from somewhere on the page).

There are real limits to this -- you have to hold the update dependency graph in your head -- but the benefits are huge for small to medium amounts of responsiveness.

My experience has been great with Rails/Turbo and htmx.

frollogastonabout 2 hours ago
I get how there's virtually no API if your client is simply rerendering the entire page each time it gets a ws message, but the article glosses over the partial page updates and just says "place the HTML where it belongs." How would that work? You'd need some kind of API for the client to request page parts and/or the server to tell the client where to place them.
x0x0about 2 hours ago
no api. The way it works is thus (rails, because it's what I regularly use):

The system is called Turbo. A turbo_frame is just a custom html element. You can largely use it instead of a div.

Turbo's js watches for navigation events (link clicks, form submits) that originate inside one of these elements, and instead of letting the browser do a full navigation, it:

1 - makes the request itself, against the usual rails routes. It uses your normal routing, sessions, cookies, etc.

2 - Intercepts the html response and looks for a <turbo-frame id="..."> that matches the id of the frame that triggered the request

3 - Swaps just that element's contents into the page.

more concretely: suppose I have a list of people in a flex table. I wrap the people table in a turbo_frame so I can prepend to it, and wrap each person in a turbo_frame so I can update it. My page can look as so:

    turbo_frame "people", class: "person-table flex flex-row" <-- the overall list
      turbo_frame person_1, class: "person-row flex flex-col"
        the row for person 1
      turbo_frame person_17, class: "person-row flex flex-col"
        the row for person 17
      turbo_frame person_12345, class: "person-row flex flex-col"
        the row for person 12345
etc.

If the user edits a form for person 12345, that is wrapped in turbo_frame person_12345.

The browser makes the request itself, grabs the response, pulls out the contents of turbo_frame person_12345 (and NB: the response can be a whole page or just this fragment), then swaps that in for the existing person_12345.

It's designed so you can make your normal MPA with page navigations and reloads for editing a table row or whatever, make a small set of updates to the html, and have this work almost entirely for free. It sounds too good to be true but I've been using it for years and it often really is that easy.

edit: for server-initiated updates, I can broadcast to select listeners:

1 - replace a turbo_frame (person_12345 was updated externally, and I want to just swap out) 2 - prepend (eg for a css table, put my new person_12345 row in front of other rows; 3 - append (same, but at bottom)

goatloverabout 1 hour ago
Is Meteor.js still in use? I recall early on it was all the rage, but that didn't last too long.

I had thought it delivered updated html over sockets, but maybe it was just the data. Did seem to be a bit more of a heavy JS framework, but it's been years.

dalemhurleyabout 1 hour ago
We have come full circle.
Advertisement
frollogastonabout 3 hours ago
So a RESTless webserver
nchmyabout 3 hours ago
In what way is it restless?
frollogastonabout 3 hours ago
Listed under advantages in the article: "State lives on the server. It is not memoryless request-response: there is a process per connected client that remembers where it is. It is the opposite of htmx, which is deliberately stateless."
nchmy7 minutes ago
but if state lives on the server and all you are delivering is html, how is that not "restful"?
bluerooibosabout 1 hour ago
Meh, just use Rails and Hotwire.
greymoonxabout 2 hours ago
What happened to the live chat xD
thiagovsdinizabout 4 hours ago
great one
odigabout 2 hours ago
so?