Hacker News new | ask | show | jobs
by zozbot234 414 days ago
> 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.

5 comments

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.

An additional one for me is stale state. I can leave most webpages open for days, except SPAs. Especially on mobile.
A small but silly one: breaking middle and right click functionality for links.

An auction site I use loads in the list of auctions after the rest of the page loads in, and also doesn't let you open links with middle click or right click>new tab, because the anchor elements don't have href attributes. So that site is a double-dose of having to open auctions in the same tab, then going back to the list page and losing my place in the list of auctions due to the late load-in and failure to save my scroll location.

I would submit this as product feedback if you haven't. One of my favorite things as a dev working on client-facing things is when I get negative feedback that presumably has a pretty easy fix to at least part of it ("add 'href' to these links") where I can pretty quickly make someone's life a little easier.
Unless it's not a link but a <div onClick={loadItem}>...
This is not exclusive with an SPA. Even MPAs/SSR apps can have this issue. But I guess MPAs are probably not built with post load interactivity in mind and maybe that's why its less prevalent there.
This issue doesn't get enough attention; apart from the obvious implications on bad UX, I find myself losing interest in a project after realising its broken in so many subtle and non-subtle ways due to the underlying tech. I, like many others, got into programming due to the joy of creating something beautiful and attempting to follow (influencer led) JS trends nearly killed my interest in this field at a time.
I still have some ptsd from payment gateway integrations via iframes about 6-7 years ago. If you thought SPAs are bad by themselves for history tracking imagine those banking iframes randomly adding more entries via inside navigation/redirection that you have to track manually.
A lot can be said for just putting a "back" button a page. I still do it occasionally for this very reason. Then again, my user base for the apps I write are the most non-technical folks imaginable, so many of them have no concept of a browser back button to begin with. I am not being hyperbolic either.
Thing is, the browser back button is still there, though. So now you have two identical buttons that do different things. And that's really bad UX.
I’m split on this. I used to agree with you but when I talked to internal users and customers, they really liked having a back button in the app. I would tell them the browser back button is there and we haven’t broken history so it should work to which they just often shrug and say they “just” prefer it.

My hypothesis is that they’ve had to deal with so many random web apps breaking the back button so that behaviour is no longer intuitive for them. So I don’t push back against in-app back buttons any more.

It's okay if both buttons do the same thing. But OP (if I understood them correctly) proposed the in-app Back button as a hacky solution to the problem of browser one being broken, which kinda implies that they don't behave the same.
I think you're right on the money—those bad web apps that told people emphatically "do NOT use your browser's back button!" did the rest of us a lot of damage, as I really do agree that it trained many people to never press it unless they actually want to leave the app they're using.

I myself am guilty of (about 14 years ago now) giving an SPA a "reload" button, which had it go and fetch clean copies of the current view from the server. It was a social app; new comments and likes would automatically load in for the posts already visible, but NEW posts would NOT be loaded in, as they would cause too much content shift if they were to load in automatically.

Admittedly this is not a great solution, and looking back on it now, I can think of like 10 different better ways to solve that issue… but perhaps some users of that site are seeing my comment here, so yeah, guilt admitted haha.

/)

Bad UX that provides a functionality that otherwise isn't there at all is still better.
> 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.

Except for a user on a lower specced device that can’t performantly handle filtering and joining on that mass of data in JS code, or perhaps can’t even hold the data in memory.
> Except for a user on a lower specced device that can’t performantly handle filtering and joining on that mass of data in JS code, or perhaps can’t even hold the data in memory.

Just how low-spec and/or how much state-data are we talking about here? I ask only because I am downloading an entire dataset and doing all the logic on the client, and my PC is ancient.

I'm on a computer from 2011 (i7 870 @ 2.9GHz with 16MB of RAM), and the client-side filtering I do, even on a few dozens of thousand of records retrieved from the server, still takes under a second.

On my private app, my prospect list containing maybe 4k records, each pretty substantial (as they include history of engagements/interactions with that client) is faster to sort and filter on the client than it is to download the entire list.

I am usually waiting for 10s while the hefty dataset downloads, but the sorting and filtering happens in under a second. I do not consider that a poor UX.

10s is painful. A server-rendered app should be able to deliver that data, already rendered, in closer to a fifth of a second. Fast enough that the user doesn’t even notice any wait.
> 10s is painful. A server-rendered app should be able to deliver that data, already rendered, in closer to a fifth of a second.

How do you know how large the dataset is? All you know from my post is that a dataset that takes 10s to download (I'm indicating the size of it here!) takes under a second to filter and sort.

My point is that if your client-code is taking long to filter and sort, then your dataset is already so large that the user has been waiting a long time for it already; they already know that this dataset takes time.

FWIW, the data is coming in as CSV, compressed, so it's as small as possible. It's not limited by the server. Having it rendered by the server will increase the payload substantially.

The JS processing and rendering time on an underpowered CPU is the issue, not the payload size. It’s difficult to describe how excruciatingly slow some seemingly simple e-commerce and content sites are to render on my 2019 laptop or how slowly they react to something as simple as a mouseover or how they peg the CPU - while absolutely massively complex and large server-rendered HTML loads and renders in an eyeblink.
What mass of data? Can you give me an example of the kind of device and the kind of use case you're talking about?
As an issue, yes, often ignored by QA, Product and engineers
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):

SPA: https://www.solidjs.com/

vs.

Poster child SSR: https://nextjs.org/

So much complexity and effort in the nextjs app, but so much slower.

> Poster child SSR

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.

Requires additional engineering.
> 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".

I think most of the thread is talking about SSR with partial HTML replacement.