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.This exactly. It seems like the last 10 years of JavaScript framework progress has been driven by DX, not UX. Like at some point everyone forgot this crap just needs to work at the end of the day, no user benefits from 3 rewrites over 5 years because the developer community decided functions are better than classes.
If you employ a "preload then rehydrate" data sync paradigm then you should never see a blank page -- except on initial JS load. This is just an improper data sync strat and has nothing to do with SPA.
I built a lib specifically designed for this strat: https://starfx.bower.sh/learn#data-strategy-preload-then-ref...
We have been moving to localized cache stores and there aren't any client side loaders anymore outside of the initial cache generation. Think like Linear, Figma, etc
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.
There's no way around waiting for the data to arrive. Being it JSON for SPA or another page for MPA / SSR. For MPA the browser provides the loading spinner. Some SPA router implementations stay on the current page and route to the new one only after all the data has arrived (e.g. Sveltekit).
> 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.