I always felt like SPAs were created to make data on pages load faster, while simplifying for mobile web, but they ended up making development more complicated, introduced a bunch of bloated frameworks, required tooling to trim the bloat, and ultimately tried to unnecessarily rewrite HTTP.
I think the focus shifted more from “need to load data faster” to “need to be able to properly architecture out frontend systems”.
Even though I still “just use jQuery like it’s 2010”, I can’t deny there aren’t problems with the ad-hoc DOM manipulation approach. One way to see this is that the DOM is this big global state thing that various functions are mutating, which can lead to problems if you’re not careful.
So some better architecture in front of that doesn’t strike me as a bad thing as such, and sacrificing some load speed for that is probably acceptable too.
That being said, “4.09 MB / 1.04 MB transferred” for the nytimes.com homepage (and that’s the minified version!) is of course fairly excessive and somewhat ridiculous. I’ve always wondered what’s in all of that 🤔
“need to be able to properly architecture out frontend systems”
“need to be able to properly architecture out frontend systems”
An absolute shitload of websites are built with React that could be built entirely with server rendered HTML, page navigations, and 100 lines of vanilla JS per page. Not everything is Google Docs.
Recent example: I recently was apartment hunting. All the different communities had SPAs to navigate the floor plans, availability, and application process. Fancy pop up windows when you click a floor plan, loading available apartments only when clicking on “Check Availability” and so on.
But why? The pop up windows just made it incredibly obnoxious to compare floor plans. They were buggy on mobile. The entire list of available units for an apartment building could have been a few kilobytes of server rendered HTML or embedded JSON.
Every single one of those websites would have been better using static layouts, page navigations, and regular HTML forms.
One reason for a lot of that is that people want to build everything against an API so they can re-use it for the web frontend, Android app, iOS app, and perhaps something else. I wrote a comment about this before which I can’t find right now: but a large reason for all of this SPA stuff is because of mobile.
Other than that, yeah, I feel most websites would be better with just server-side rendering of HTML with some JS sprinkled on top. But often it’s not just about the website.
I don’t think an API and server-side rendering have to be incompatible, you could just do internal calls to the API to get the data to render server-side.
That’s what we’re doing. We even make a call to API without HTTP and JSON serialization, but it’s still a call to an API which will be used by mobile app.
Having done this, I feel this is the way to go for most apps. Even if the backend doesn’t end up calling a web API, just importing a library or however you want to interface is fine too, if not preferable. I’m a big fan of 1 implementation, multiple interface formats.
I agree. So, to answer the titular question, I would answer: websites and native applications.
Developing “stuff” that feels like a website fitting the HTTP paradigm is mostly straightforward, pleasant, inexpensive, and comparatively unprofitable.
Developing “stuff” that feels like an application fitting the native OS paradigm is relatively straightforward, occasionally pleasant, often expensive, and comparatively unprofitable.
If we’re limiting our scope to a technical discussion, it seems straightforward to answer the question. Of course, for better or worse, we don’t live in a world where tech stack decisions are based on those technical discussions alone; the “comparatively unprofitable” attribute eclipses the other considerations.
That’s how I remember it. I also remember building SPAs multiple years before React was announced, although back then I don’t recall using the term SPA to describe what they were.
is there a reason why mutable state on the server is avoided (in the phoenix live view section)? I understand why it’s bad to have state on both sides, as you then have to keep them in sync, but is there a reason why server-side-only state would be worse than client-side-only?
The biggest reason I can think of is scaling horizontally. If I’m not maintaining state on the server, I can simply put more of those servers and front it with a loadbalancer. I don’t care which one of them services the client, since it’s all ultimately in the database.
The only reason I can think of is proper use of REST API on the server. Or any similar situation where state on the server ties you to that server for the remainder of your session.
There’s only one client. Keeping the state in the app can be tricky to scale up. The user’s network connection is now tied to the stateful app layer, instead of in a database serving hundreds of app servers. A lot of work has gone into phoenix to make this work reliably, and it is pretty opinionated about how it needs to be deployed (no Heroku or other “serverless” unless you want Redis in the middle).
What’s wrong of having Redis (or other queue) in the middle? Aren’t you going to use it anyway?
Nothing wrong with redis, though it was very difficult to setup HA last time I tried. It’s more about the native BEAM distribution being fully sufficient, Redis is an extra component that would serve no purpose if not for the limitation that the app servers can’t communicate directly with each other using the network. It also introduces a SPOF. Redis isn’t as common with BEAM apps, between mnesia, ETS, and genservers, it’s pretty easy to keep your hot state where you need it.
So, phoenix liveview does make use of erlang/elixir’s distribution facilities to make the session state available to all servers, is that what you’re saying? If so, it explains why it’s not more common in other languages :-)
Yes, though LiveView and Presence have a lot of work on them to make it possible, like using CRDTs to sync state between nodes. BEAM distribution just makes it easier to communicate with other nodes in the cluster.
I don’t think the point of SPA’s was to simplify web development, I think it’s more just to create a smoother UX.
I’m attempting to chip away at a bit of this problem via an unopinionated “Modest progressive-enhancement” approach that aims smooth the transition between classic backend-rendered apps and SPAs. I think “have the luxury of operating on a deeply improved web stack” is key here, you can get very far these days without pulling in the kitchen sink.
I haven’t done any SPA projects, but just from thinking about it, it feels a little over complicated. Easier to keep things separately.