> As a user, the typical SPA offers a worse experience.
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, pure old school SPAs have at least one additional roundtrip on the first visit of the site:
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.
> Your typical SPA has loads of pointless roundtrips
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.
> Your typical SPA has loads of pointless roundtrips. SSR has no excess roundtrips by definition
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".
Requires additional engineering.
My biggest annoyance with SPAs is that they usually break forward/back/history in various subtle (or not so subtle) ways.
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.