But I guess now with things like Supabase joins in the front end are normal?
It's weird how these things change. But regardless, worth noting that people are using "frontend" to mean different things.
https://supabase.com/docs/guides/database/joins-and-nesting
"The data APIs automatically detect relationships between Postgres tables. Since Postgres is a relational database, this is a very common scenario."
There will be many people with the title Full Stack or Front End engineer who are using Supabase in this way and they may consider the code that triggers this to be front end code. There might or might not be another engineer who is in charge of the database and does some coding for it but always refers to him/herself as "backend" and is not aware that some of these joins are happening and need indices.
Very common in companies that keep their backend and frontend teams separate or companies with very dogmatic backend people.
SPAs are only a good idea if you ignore all the complexity required to make them actually work decently - like carrying over the whole data model all the way to the frontend app.
Even back in the multi-page application days people doing large apps were already splitting their code MVC style with a model-layer that functions much like an API layer does today in an SPA.
Most devs don't understand that some techniques just don't work after a certain point and others are too complex for simple use cases. Everybody wants their silver bullet...
It used to be, a page that was primarily rendered on the server but used javascript for dynamicism in the frontend was still considered SSR. nowadays people try to relegate SSR to only rendering on the server, but that's never been the case and is a strawman.
I have no good answer for what makes sense but I usually straddle 2 and 3.
3 seems to be the most pragmatic option to me when you have good control over each side.
At some point there will be a need for some "bloated" API requests. GraphQL can help minimize how many of those you need.
My suggestion in these cases, is to give the front-end devs a node/express server where they can compose the API calls the way they like and consume that from the webapp. But... they have to own it.
At a job I worked at "fix it in the frontend" was a running joke.