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.
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.
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.
https://en.andros.dev/blog/bd74e61a/were-fighting-over-the-w...
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.
Overhead, security, denial of service.
You now have two states to track. Is the web-server up to date with the version that the web socket is rendering?
Is your monitoring suffice? Is your web server going to be alive if the web-socket server is offline? How do you determine if the socket server is actual offline and not frazzled itself in an event-loop?
If both your web socket server and web server are going to follow both the same source of truth for fail-over why not just use the web-server? A tried and true method of serving websites as well a application that is easier to cluster, load balance and all the other security bells and whistles.
The best part is than you can actually serve a website without requiring JavaScript.
If corporate firewalls are blocking web sockets, how do you determine this? As any request you're going to be rendering blank back to the client.
There isn't any easy way to determine if the client is blocked.
You still need something to serve the JavaScript fronted of the website 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 idle wasting resources.
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, how do you determine if the web socket is actually dead or not an attack? More complexity.
It's not wrong, but a waste of time, resources and the overhead of it all just isn't worth it.
Furthermore any alterations need testing on both parts If a hotfix is required on the web-socket side.
Until someone bombs your websocket server and you then have nothing at all.
Just make a normal website!! You've invented an MPA with extra steps!
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.