I think the DX is significantly better as well with fast reload…
As a user, the typical SPA offers a worse experience. Frequent empty pages with progress bars spinning before some small amount of text is rendered.Your typical SPA has loads of pointless roundtrips. SSR has no excess roundtrips by definition, but there's probably ways to build a 'SPA' experience that avoids these too. (E.g. the "HTML swap" approach others mentioned ITT tends to work quite well for that.)
The high compute overhead of typical 'vDOM diffing' approaches is also an issue of course, but at least you can pick something like Svelte/Solid JS to do away with that.
Yes, I know that this can be made to work properly, in principle. The problem is that it requires effort that most web devs are apparently unwilling to spend. So in practice things are just broken.
This is an implementation choice/issue, not an SPA characteristic.
> there's probably ways to build a 'SPA' experience that avoids these too
PWAs/service workers with properly configured caching strategies can offer a better experience than SSR (again, when implemented properly).
> The high compute overhead...
I prefer to do state management/reconciliation on the client whenever it makes sense. It makes apps cheaper to host and can provide a better UX, especially on mobile.
1. Fetch index.html 2. Fetch js, css and other assets 3. Load personalized data (json)
But usually step 1 and 2 are served from a cdn, so very fast. On subsequent requests, 1 and 2 are usually served from the browser cache, so extremely fast.
SSR is usually not faster. Most often slower. You can check yourself in your browser dev tools (network tab):
vs.
Poster child SSR: https://nextjs.org/
So much complexity and effort in the nextjs app, but so much slower.
That's not really SSR though, it's partial SSR but then hydrated into a client-side React app, so a SPA. If you really want to compare try an htmx page.
SSR also has excess round trips by nature. Without Javascript, posting a form or clicking a like button refreshes the whole page even though a single <span> changed from a "12 likes" to "13 likes".
Please forgive the self-promotion but this was exactly the premise of a conference talk I gave ~18 months ago at performance.now() in Amsterdam: https://www.youtube.com/watch?v=f5felHJiACE
It just depends on what you are after. You can completely drop the backend, apis, and have a real time web socketed sync layer that goes direct to the database. There is a row based permissions layer still here for security but you get the idea.
The client experience is important in our app and a backend just slows us down we have found.
you might be able to drop a web router but pretending this is "completely drop[ping] the backend" is silly. Something is going to have to manage connections to the DB and you're not -- I seriously hope -- literally going to expose your DB socket to the wider Internet. Presumably you will have load balancing, DB replicas, and that sort of thing, as your scale increases.
This is setting aside just how complex managing a DB is. "completely drop the backend" except the most complicated part of it, sure. Minor details.
Which is fine and cool for an app, but if you do something like this for say, a form for a doctor's office, I wish bad things upon you.
That's never the case.
I built a lib specifically designed for this strat: https://starfx.bower.sh/learn#data-strategy-preload-then-ref...