- What happens if the client’s internet connection temporarily drops? How do you handle client reconnections and retries?
- What if the remote server crashes through no fault of your own (AWS server rack catches fire)? How do you ensure a consistent reconnection that preserves application state?
These are just two questions that HTTP + Browsers solved decades ago.
Websockets are this cool technology that seems powerful and exciting until you realize the “boring old stateless World Wide Web” was built over decades of iteration using stateful sockets as the backbone, did most of the work for you in tandem with browsers, and is ultimately a lot cooler and more sophisticated than a lot of us give it credit for.
Imagine a few customers open up your site and leave for lunch. Or maybe just a random crawler or bot sitting watching for some piece of information they are scraping.
These sorts of issues can be challenging with stateless connections. I can only imagine how daunting they are with persistent connections.
Games basically do this routinely.
What happens if a webpage is loaded over plain old HTTP and then over lunch a breaking change is deployed. The page the user loaded before lunch is now no longer compatible.
It’s stateless. If the api changes from underneath and you’re polling or something, then just show an error, have the user refresh the page and move on. Or use any of the various api version mechanisms for backward compatibility. It’s not an easy problem but it’s a fairly well understood and managed one. Solving this kind of known problem isn’t, to me, a very compelling case for HTML over sockets.
With server-fed, event-driven pages, you could potentially force refresh.
I assume web-sockets could make it work more robustly.
A crash or someone hitting refresh on his browser is not that different in this respect.
WSs aren't a magic wand, they just allow you to do more with the same.
You basically end up with a half-assed, buggy, and potentially insecure reimplementation of HTTP running over web sockets running over HTTP at that point.
Are you going to do session management and identification by issuing a unique identifier as well? Is that unique identifier going to be valid in perpetuity or have a an expiry date? Is it going to be valid and secure across all sub-domains or will it be prone to cross site scripting attacks?
The purpose is in the things explained well in TFA: single source of truth, no replicated state, simpler development, and so on...
Who said the purpose would/had to be in handing "the server caught fire" scenarios?
It works for certain things and not for others. So, it's not "the future of web software" like the title says, it's one additional possibility for when it makes sense.
Because you can do things stateless HTML alone cannot do.
No one is trying to re-implement HTTP, or even remove it from the equation.
What people are trying to reimplement (or rather, replace) is the HTML + JSON:API + React + Redux mess. Websockets is a means to that end.
Unfortunately, great intentions alone won’t make this work; someone has to actually answer the hard questions about how it’s going to work too.
All the answers I’ve seen so far trying to answer them have been vague hand waving...
That doesn’t leave me with much confidence.
People did better than that, they already built applications with this model.
Here is the documentation for Phoenix channel authentication (what Phoenix Live View is built upon): https://hexdocs.pm/phoenix/channels.html#using-token-authent...
Additionally, here is some documentation on the security considerations specific to Live View: https://hexdocs.pm/phoenix_live_view/security-model.html
Searching can probably find you more information.
I should probably already know this.
HTTP is quite literally "hypertext over sockets" so "HTML over websockets" is functionally equivalent... with a layer of abstraction added on top. If you build web software by sending HTML over websockets you're just reinventing what already exists; it's probably why it's never taken off. I think most developers realize within ~weeks to months of working on a "websocket-everything" framework that they're doing more work, not less.
Why would you? Nobody seems to ensure that with regular SPAs anyway...
Seriously, try phoenix liveview if you haven't already. These problems of dealing with stateful connections over questionable tranport and managing them are what the Erlang vm were designed for, and phoenix was designed by rails core team members.
If you instead have servers holding state, those servers become a lot less ephemeral.
In addition, HTTP has built in caching, which is a HUGE benefit for scale.
it works okay in small clusters on reliable low latency networks but it's not a replacement for an actual network mesh
there have been attempts to fix it but none have really found adoption. i think this is the most notable: https://lasp-lang.readme.io/docs
Wouldn't an intermediate layer such as e.g. Phoenix/LiveView (https://www.phoenixframework.org/) solve the problem?
I don't think so but if I'm wrong please correct me.
For example, imagine this simple scenario: you load the comment page for this post on HackerNews
HackerNews renders an HTTP response to your browser and your browser renders the page based on that HTTP payload.
You can be sitting here on the page for 10 minutes reading comments and even if HackerNews randomly went down 20 times for 10 seconds each time during those 10 minutes you would never know because your browser has everything it needed to render the page when it loaded. It's a done deal. The request was made and the response was served.
But now let's say you use LiveView and you made this page an actual Live View. Let's also say you load all of the comments at once to keep the example the same.
Since there's a persistent websocket connection open at all times, in all 20 cases of HackerNews going down you're going to get a visual warning that the websocket connection was dropped. You also don't want to disable this visual warning because on slower devices it might take 2 seconds to load the page which is much different than an uncontrolled disconnect.
IMO this user experience is pretty bad. Why should users be concerned with the server's state after it has everything it needed to handle the request it asked for (loading the comment page). If they try to post a comment and the server is down then the user should see that error at the time of them making the comment (such as a custom 502 error page if the back-end is down).
The grandfather's comment of "it wasn't designed this way by accident" is spot on. The stateless web is a happy web. Sure you can sprinkle in websockets for progressive enhancements like broadcasting new content somewhere (which is awesome when done well), but websockets shouldn't be the basis for everything. HTTP has decades of very careful thought and optimizations around its protocol.
I understand you needed an example, but a better comparison would be a heavy SPA with real-time interactivity. In that case, if your server is down your API calls will fail and you're going to have to handle the failure and let the user know something went wrong any way. If anything, Live View's built-in buffer and retry can actually provide a better user experience because the UI will automatically "catch up" when the client reconnects.
> You also don't want to disable this visual warning because on slower devices it might take 2 seconds to load the page which is much different than an uncontrolled disconnect.
Live View loads the entire initial page over HTTP, then mounts the Live View. Your slow device won't see any difference if the visual warning is disabled or not.
It's because the creator of Live View himself said he's not going to be using "dead views" anymore for sites that don't need offline capabilities or are clear cases where LV would fall apart. He's advocating for everyone to use LV instead of regular views even to serve HTML for most sites.
I can see the appeal too, Turbolinks did a great thing a few years ago by improving page load speeds by turning regular HTTP requests into ajax calls behind the scenes and then swapping the <body> of the page, all without having to write a single line of code beyond importing the JS library and without having to change anything on the back-end.
With LV's live_redirect you can get a similar effect. It's a much different implementation (way more changes are needed on the back-end) but the end result is similar'ish.
And if you had a site that benefits from speedy page transitions (aka pretty much every site) and you happen to have a few cases where using LV makes sense such as wanting to do real time validations or show a stream of something then it would make sense to want to go all-in and use LV to serve every page so that you don't need to bring in both Turbolinks and LV as dependencies and still benefit by having fast page transitions across your site.
I have bad news for you about how often most web developers are using React.
It's due to Live View triggering a visual indicator that the websocket connection isn't available.
It's a combination of CSS and JS. You can turn this off but if you turn it off then you have no way to show an indicator when you do care (such as transitioning between pages or submitting a form).
I don't think LV at the client level can be coded in such a way that it can tell the difference between the server dropping and the user's connection dropping due to their internet being spotty.
To the rest...that's the point, it's just...CSS and JS. You can change it. You can show it or not, based on what the user is doing, or what view they have. Worst case, you can just hide it completely across everything, as you say, which is then no different from an SPA, except where functionality fails when you have no connectivity. Whether that leads to a better or worse user experience is dependent on the dev's handling of those failures.
You can restrict the visual warning to the first load only, it would be pretty distracting otherwise.
How would this work in practice while still showing it when you want it to be shown?
A feature that protects from ridiculously unlikely problem is no feature. It is over engineering
You could have incompetent engineers or you could have bad internet. The user could be on a train that is going in and out of tunnels. Or the user could be in a house using WiFi and the microwave could be causing interference.
If you want to do requests in parallel, http 2 and 3 can do them just fine. If it’s sequential, you won’t see a huge difference between something on websockets and http/1.1.
The only thing you can save are a few header bytes. And it’s up to you how many headers you use
If you have authentication then cookies have to be going out also and any other information that has to be kept in order to provide state over a stateless connection. You still need to handshake on each connection (maybe http2/3 bring this down a bit), and you also don't have bidirectional flow, so if you need something resembling client side "real-time" functionality you now have to implement pooling, or server side events.
The biggest issue is basically how to load balance/scale and that becomes a problem only given a scale that 98% (scientific) of the websites online won't ever experience.
You can just use one connection (same as websockets)
> and you also don't have bidirectional flow
Sure you have. Each request and response has a body, and HTTP bodies are indefinite streams of data. You can do everything in them you like (including running your custom protocol). That's e.g. how gRPC streaming works.
And keeping one connection then we're in the same spot regarding the scaling issues as with web sockets right? Or does plain TCP/IP have better support for changing endpoints mid-flight, reconnections and etc?
Although if so I don't understand why there was even the need to come up with Websockets? I personally would love to see a simplification of technology all across OSes, web, etc, but probably there's too much out there to provide a reasonable migration path... It sometimes feels like those projects that you work on in the beginning and then you look at, some years down the line and say, this needs a refactoring with all I've learned in the meanwhile regarding what I'm doing and regarding my understanding of the domain space - but sometimes you can't do it, doing it might not go well or you'll end up in the same place afterwards.
And note that we're not talking about parallel request, those are not relevant to the "constant stream of small updates as the backend state updates" model described in the article, so let's not get side tracked, and talk about the actual stream of small fragment data in HTTP vs websockets.
Every HTTP connection (whether it's v1.1, v2, v3, or some even newer Google-flavoured "we came up with another one!" version) requires secure connection handshaking before any actual data may be sent. And if you're using any kind of session management, which you will be, now you're also spending time on cookie transmission before you get to payload transmission. And yes, there is the "Connection: Keep-Alive" header that can be set to allow more than one request per established connection, but any sane setup has that either on a small timeout (hundreds of ms at most), or on a low number of requests. You're still going to be establishing lots of connections, over and over, during the lifetime of the content at the client.
So, for many payloads a lengthy (compared to small payload transmission) HTTP connection negotiation has to happen. This is not the case for websockets, which by design are as if the "keep-alive" was set to "forever": they get initiated through a one-time HTTP call that contains an "upgrade this connection to a websocket" instruction header, after which we're done. This is now an open, persistent, bidirectional data socket.
Connection-wise, the amount of time required for HTTP vs. websocket is immense.
Secondly, let's not try to lend credence to an argument by hand waving the number of bytes in headers: the model discussed here concerns pushing small fragment updates to the client, in which headers constitute a significant part of the transmission. You can see this is modern sites that communicate small JSON fragments today where payloads like `{"error": false, "result": 12}` get dwarfed by the modern response headers, because yes "you control yoru headers" but you're not running your first server (in fact, you're almost certainly not running your own server at all, you paid a host): a response will contain not just the HTTP version and content type and length, but also the cache control value, the CSP and CORS headers, and almost certainly some extra stuff like the datetime, cookie expiration, x-frame-options, etc.
Using websockets makes an incredible difference in the model discussed in the article.
However, if you want to discuss the merits of the two completely different models, that's fair. Why would you even use the small-payloads push model? Who cares if the client has some state that "hopefully" mirrors the server? These are good questions, and unless you're writing a multi-user application with a web front-end, I genuinely don't see why the approach outlined in this article makes much sense.
Yeah, React kind of shat all over the web (and I say that as someone who quite likes React) because it was never designed with the purpose of generating web content. It was born as an interface library and never stopped being one. Its fault is being so damn easy to pick up which means that every site on the planet now uses React to build normal web pages and even do page routing, instead of having the devs write their code in React and then hitting the "and now generate that as static site with vanilla JS for the interactive bits" button. Because that button doesn't exist, instead it's esbuild (or previously, babel+webpack but thank god esbuild now exists so we don't have to use that anymore).
But that's a completely different discussion and really not related to how websockets are incredibly much better for the stateful server, thin client, many-small-updates push model.
For all of the stateless goodness that HTTP is, in order to have user-specific content, you need to know who you're talking to. The hack to fix this was cookies. Instead of using a traditional stateful protocol (which could have kept track of the logged in user), we had a stateless protocol where the user basically had to present credentials with each request (also, HTTP-AUTH).
The second issue was so problematic that it made it into HTTP 1.1 two years later. Because a stateless protocol was used, if you wanted to download say, a document and a linked image in the document, in HTTP 1.0, you needed to make two requests. Back when each web page was predominantly text with few graphics, this was okay. When we moved to more graphical (albeit table-based) layouts, this was horrible. So, HTTP 1.1 ushered in Connection: keep-alive to allow for the same connection to be used for multiple requests. You still had to make individual requests, but at least you didn't have the overhead of setting up multiple TCP connections.
HTTP isn't fundamentally broken, but it is a kludge. The most painful parts of HTTP were also the most "stateless" aspects. I agree I don't understand why HTML over Websockets is a (big) thing. It doesn't make much sense to me either. Then again, I was also doing dynamic updates (with javascript pulling in HTML, not XML) before A List Apart (hello again) coined the term AJAX.
But let's not just say that HTTP is a perfect stateless protocol. It isn't. It was never "designed this way" -- it was patched up with quick fixes during the late 90's that we've been stuck with ever since. Websockets is the latest attempt to fix this problem. HTTP/2 and /3 don't really do anything to address maintaining session state, but focus on making individual request more efficient (roughly). That still leaves us with the problem of Cookies. Websockets have their own issues (scaling for one), but adopting the approach mentioned in the article doesn't mean that you have to completely abandon the rest of HTTP. But, if I could avoid having every website yelling at me about using cookies, I'd happily adopt a Websocket architecture, if that's what it took.
> That still leaves us with the problem of Cookies. ... But, if I could avoid having every website yelling at me about using cookies, I'd happily adopt a Websocket architecture, if that's what it took.
This is a red herring. If "the problem with cookies" is that websites yell at you about using cookies, that's a legal issue with the requirement to notify users they are being tracked. This "problem" of being yelled at didn't exist before the legal requirement.
Moving the transport to websockets (layered on top of HTTP, layered on top of TCP) doesn't get rid of the legal requirement for notification or opt-out. It just buys some time until the law catches up and says that the state management you're using with websockets is also subject to tracking notification and opt-out.
It’s not a red herring. And it’s not the website warnings that are the issue, it’s the tracking that they have to notify you about. If we didn’t have to allow cookies for basic interactions with websites (like a session cookie), then we wouldn’t need to allow tracking cookies at all. However, because we need to allow session cookies, other sites can then track us.
With a persistent connection/session, this wouldn’t be necessary.
But clearly, there are many other ways to tackle this problem. And the persistent socket connection also has issues. But after thinking about this, I think the company behind the current dominant browser may be a little conflicted about solving this issue. I’m hopeful about Firefox’s new approach.
In fact, you'll probably find you'll need to store some tokens on the client, somehow, just to secure the client/server connection.
It's possible but extremely difficult to create a "modern" experience with just html. Just like how we don't build houses with mud-bricks anymore even though it's easier than steel and wood.
I have a personal toolkit of components I call "you might not need Javascript". Dropdowns, slideovers, toggles, modals, tabs, accordions, autocomplete, lightboxes, all with nice transition animations, and all in pure server-rendered HTML+CSS. A lot of it is just semantic elements being used appropriately. How many developers use <datalist> or <summary>/<details>? or :target and :focus-within? In my experience, not enough. How about, using <details> in combination with a CSS [open] selector? The palette gets rich in combination.
Overall, no, it's not hard, but it does require one to study. A couple of times a year, I'll re-read through the HTML LS and CSS specifications. There's a lot in there to build from, and almost all of it has broad evergreen browser support. For the leading-edge stuff, "caniuse.com" remains an essential reference. I currently have my eye on the <dialog> element, high expectations there, works well already in Chrome; Firefox just has a couple of bugs to shake out, and it's experimental (but incomplete) in Safari.
All that said: a light dusting of JS can still provide progressive enhancement, but we can limit this to minor cosmetic improvements & optimizations, for browser compatibility, and where dynamic ARIA markup is necessary.
The motivation as to why I prefer this style is another matter, and it's do with product strategy, and in particular, not crystallizing your architecture in the front end (where it is brittle) but in the backend (where it is much faster to pivot and/or rapidly prototype/spike/redevelop, by proximity to business logic and persistence schema). These are understandings that've been long (and sometimes painful) in the learning, but they're pretty much universal.
What is HTML LS?
"Modern" experience is not necessarily the same as "good" experience. Good old server side rendered pages are fine; SPAs are being built just because "we can", not because they are actually needed (sure, in some cases,SPAs are needed, e.g., chat sites).
I have yet to see a proper web app (not a blog/collection of static pages, but something that does something complex like let you manage inventory, do payroll, do your taxes, monitor sensors in real time, interact with geographical maps, or edit documents) that is done without JavaScript and has even OK UX.
SPAs are great because of separation of concerns. Sever takes care of the data (storing it, syncing it, authenticating your access to it, serving it, sharing it). Client takes care of presentation. I build SPAs because they are better. Imagine if all the apps on your phone or computer were effectively HTML documents rendered on the server. Emacs over HTML/CSS? Minesweeper? World of Warcraft? Would that be an OK experience? Probably not because you don’t want to wait for a page load every time you do something in your Minesweeper game or check stock prices or whatever. Why should web apps be inferior?
When people complain about SPAs it’s because they don’t like web apps running in the same environment as their document-based content. I guess some people prefer the ActiveX/JavaApplet model, which to a degree I can understand. Slack is an application, not a website. But let’s not overlook the fact that implementing a Slack client with just HTML and CSS would be miserable to do and miserable to use.
Inferior compared to what?
I'm not going to call your statement nonsense but unless you have proof that SPAs make up the majority of the websites/web apps online today, I'm afraid I must disagree.
Frontend dev is a hot mess of garbage JS cobbled together to make a psuedo native experience.
> but something that does something complex like let you manage inventory, do payroll, do your taxes, monitor sensors in real time, interact with geographical maps, or edit documents) that is done without JavaScript and has even OK UX.
This is not what the web was built for. The same things you mention dismissively (server side Static pages) are the core and norm ,by and large, the vast majority of what constitutes "the web"
Good, lightweight native apps can do all the above without breaking a sweat, and you can have multiple native clients for things you care about. I don't always have an internet connection but I still want to type my documents. I fire up word. Not google docs. I need to do some serious data wrangling - I fire up excel not google sheets. Need to do some networking for my router, wireshark. Need to read an ebook - adobe acrobat. Need to write some shader code - Sublime text.
So the way it looks to me that SPAs are trinkets - not at all mission critical beyond loading cat pictures faster or bending the web backwards to do things it wasn't supposed to. Server side static pages rule the web.
Complexity is just a good way to justify a large paycheck.
The second argument is that there isn’t a technology today that supersedes the web in one crucial feature: no installation required and updates are transparent. Various app stores are trying to solve this in a platform specific way but do you really want to live in a world where to publish an app you must include Apple and Google and Microsoft in your deploy path? You and I may be able to go to GitHub and download OpenStreetMaps code, then download all the data, install it all locally (most of the documentation last I checked was still in German BTW), and then use it to find directions to the nearest Starbucks. An average user will give up before spelling out “GitHub”. If you can point at any platform that lets me type in the name of an application and stat using it in under 1 second without installing anything whatsoever on my system, I will eat my hat.
That isn’t to say that we can’t have nice things. With time and effort you can create such a platform and get all OS vendors to support it and all the developers to move to it. But I will postulate that fixing the JS frontend mess will take at least an order of magnitude less effort. Therefore the web is where these types of applications will live.
Again I am not talking about things that are static. This isn’t about a blog. This is about whether a real application is better server-rendered or as an SPA and I argue that in 99% of cases an SPA will be a cleaner architecture AND provide better experience to the user. The fact that coding one up is annoying (arguable at best) is a temporary tooling problem, not a fundamental design flaw.
Top Gear proved it was well and truly possible. It's a popular mode of transport. It carries things. It has an engine and a mostly metal body.
It still isn't quite a boat
Web apps can walk and talk like native apps, but they aren't. Sure one off things like a Facebook or spotify or meme generators can rightfully be served from a web app - but applications for computing and getting work done?
Oh and don't forget about mobile devices - what amount of web apps do you prostulate people use there?
> SPA will be a cleaner architecture AND provide better experience to the user.
This. This is nonsense.
I will point out that I routinely use Reddit on mobile Safari and it is most certainly a web app. Things like Twitter, Facebook, etc. are also apps, and while you can download a native version, for privacy reasons I prefer their web app counterparts as they are less able to spy on what the rest of my phone is doing.
I will also again point out that Google Maps is a better experience than downloading OpenStreetMaps and setting it up yourself. Even something like Slack and Discord and Google Docs are perfectly good experiences on desktop browsers and require no installation whatsoever. You aren’t really addressing the zero installation point at all and that’s at the crux of why web apps are a thing and their main draw. You quoted my conclusion and called it nonsense without any basis since you provided a straw man argument and didn’t address the main point at all.
The server side is being broken up into micro-services which makes all server a client/server roundtrip as well. Your DB was always running seperately making it a client/server roundtrip, etc.
Maybe I'm missing something, but what aspect of client/server is overly complex? And why is websocket (a client/server roundtrip mechanism) any easier?
The backend is likely all in the same building with a reliable and high-bandwith link between servers.
You can't compare that to a round-trip from the client to the backend.
Here is a short demo of the product: https://www.youtube.com/watch?v=TwkgGBrK_tA
Say you have a doctor that is associated to a group of patients and is allowed to update their patient's status. And if, while the doctor is filling something out for that patient, the patient changes doctors, then the current operation has to fail and the doctor needs to be notified of this change somehow.
So what do you do with the stale list of patients in the browser DOM?
Does the UI wait to see if the write fails, or does it increase reactivity by supporting a server push? And how do you tell the DOM to update the list of menu items so that that Patient X is removed from that list? What if half the doctor's patients have been removed? Does the UI wait for the doctor to try to make some change to all of them and one by one remove a patient or does it reload the full patient list? And if so, how often does the browser poll for the full the patient list -- during every operation involving a patient?
The server push reduces the amount of time wasted by the doctor filling out stuff for a patient that will be refused by the server anyway, and it avoids costly polling, reducing bandwidth. I get that it may not be worth it, it depends on how important reactivity and bandwidth are to the app, which is why videogame makers need to do it but people writing marketing pages don't.
Either way, you have a stateful connection as the set of patients available to that doctor is important connection state that can change at any time. So you are long past the idea of REST whenever you start building an interactive UI with data that must be synced from a remote server.
I am not a fan of the server push, but I feel that ship has sailed and people are adding in a lot more complexity for the sake of improved reactivity. My personal rule of thumb would be to always sacrifice reactivity for simplicity, but then this is why I don't build marketing pages.
Write the front end in something like Vue. When you catch an error from an axios call, update your data model by calling the server for updates.
When the data model updates, Vue will automagically update the DOM used by the browser.
Then again, it wasn't designed this way to build applications with, either. It was designed to serve documents (the HT in HTTP).
It uses websockets & JSON to connect the SPA UI (in Vue.js) to the app (in Go). That works well, and I can't imagine any advantages to generating HTML with Go, except perhaps less JS code :-)
All the problems with a stateful connection are solvable, but we have yet to figure out the right way to teach the discipline of doing it right. It is an exceptionally expensive proposition to solve, so most people shouldn't solve it as they will be picking up a huge bill.
The challenge is that HTTP is fundamentally broken for stateful experiences, and people are trying to build that into everything these days. They want shit to update across machines, and polling is exceptionally easy at great cost.
Let's not go there again. It's the definition of worse than flash. And mostly for above described reasons.
Networking, Animation, Transitions, APIs, State of Data, State of Synchronization, Unpredictability and Unreliability of UI/UX States... all mixed together in a single socket.
Have fun debugging this blob of autogenerated code and transactions.
[1] www.gwtproject.org
Normally I’d agree with your take entirely and I don’t actually think it’s possible to avoid the complexity issues in non-BEAM languages...but Phoenix is absolutely doing it.
Multiplayer online experiences are also growing to include more than gaming, such as betting and gambling and zoom and trading crypto.
Are websockets and or browsers improving to handle this server centric shift?
The complexity benefit of having stateless HTTP transactions is vastly offset by the statefulness of TCP, TLS states, HTTP "sessions", cookies, browser storage & so on.
HTTP is hardly "designed" and plenty of its aspects were accidental.
The problem is that stateful connections suck and create artificial complexity when you don’t need them. Instead of managing the state of your app you’re now managing the state of your app and a connection to a remote server. HTTP is a stateless protocol on top of a stateful socket connection. It wasn’t designed this way by accident.
I’m all for new engineers building SPAs creating exciting new libraries, but HTML-over-websocket has been rehashed at least three times over my professional career so far and it’s not even that long.
Don’t get me wrong — websockets have their use cases. Multiplayer online experiences pretty much require them. It’s just that HTTP isn’t fundamentally broken, and by engineering HTML over websockets you’ll almost universally find yourself building protocols to abstract the state away... re-engineering HTTP in the process.
It’s certainly a fun project which I have personally worked on. But I’m not sure it has legs outside of that. Open to being proven wrong, the authors of HTTP aren’t infallible.