Comment by simonw

4 years ago

It's been so frustrating watch this play out over the past decade.

I keep seeing projects that could have been written as a traditional multi-page application pick an SPA architecture instead, with the result that they take 2-5 times longer to build and produce an end-result that's far slower to load and much more prone to bugs.

Inevitably none of these projects end up taking advantage of the supposed benefits of SPAs: there are no snazzy animations between states, and the "interactivity" mainly consists of form submissions that don't trigger a full page - which could have been done for a fraction of the cost (in development time and performance) using a 2009-era jQuery plugin!

And most of them don't spend the time to implement HTML5 history properly, so they break the URLs - which means you can't bookmark or deep link into them and they break the back/forward buttons.

I started out thinking "surely there are benefits to this approach that I've not understood yet - there's no way the entire industry would swing in this direction if it didn't have good reasons to do so".

I've run out of patience now. Not only do we not seem to be learning from our mistakes, but we've now trained up an entire new generation of web developers who don't even know HOW to build interactive web products without going the SPA route!

My recommendation remains the same: default to not writing an SPA, unless your project has specific, well understood requirements (e.g. you're building Figma) that make the SPA route a better fit.

Don't default to building an SPA.

> And most of them don't spend the time to implement HTML5 history properly, so they break the URLs - which means you can't bookmark or deep link into them and they break the back/forward buttons.

The majority of routers for React, and other SPA frameworks, do this out of the box. This has been a solved problem for half a decade at least. A website has to go out of its way to mess this up.

That aside,

SPAs are great for a number of reasons:

1. You aren't mixing state across server and client. Single Source of Truth is a thing for a good reason. If you have a stateful backend, and your front end naturally has the state of whatever the user has input, you now have to work to keep those two in sync.

2. You need a beefier backend. A SPA backed by REST APIs is super easy to scale. nginx can serve up static resources (the JS bundle of the site) LOLWTF fast, and stateless REST apis are easy peasy to scale up to whatever load you want. Now you just have to worry about backend DB, which you have to worry about with non SPAs anyway.

3. Less languages to deal with. If you are making a modern site you likely have JS on the front end, so with SPA you have JS + HTML. With another backend framework you now have JS+HTML+(Ruby|Python|PHP|C#|...), and that back end code now needs to generate HTML+JS. That is just all around more work.

I agree some sites shouldn't be a SPA, a site that is mostly text content consumption, please no. A blog doesn't need to be a SPA. Many forums, such as HN, don't need to be a SPA.

But if a site is behaving like an actual application, just delivered through a web browser, then SPAs make a ton of sense.

  • Your arguments seem to be assuming a particularly bad implementation of a traditional backend.

    1. A good server-generated-HTML backend will have no more state than a good server-generated-JSON backend. The client state is all stored in the client either way, whether in JS variables, HTML tags, or the URL.

    2. A good server-generated-HTML backend doesn't do significantly more work just because its output is in HTML instead of JSON. A bit of extra text generated isn't going to increase your CPU load in any meaningful way.

    3. There are only fewer languages to deal with if you aren't in charge of writing backend code. If you're in charge of the backend code, you still have to pick a backend language for your JSON API.

    I think you're assuming that the choice is "SPA" or "messy stateful monstrosity". It's perfectly possible to build a RESTful HTML-based API that is as clean and stateless as any JSON API. PHP's been starting each request with a clean slate for decades.

    • Your arguments seem to be assuming a particularly bad implementation of a traditional backend.

      Whenever someone says "this particular architecture is bad!" they're talking about a bad implementation of it.

      The point is whether or not you're more likely to succeed at making a good app with an SPA or a multi-page site. For pretty much all brochure-styles websites and many SaaS webapps you're more likely to achieve success (for every common understanding of success) by using a multi-page architecture because they're usually simpler to implement, they work the way browsers expect things to work, and you don't need to implement some hard things yourself. You can make a brilliant SPA website for any purpose, but often people try and fail. Saying "you shouldn't have used an SPA" is shorthand for "You didn't understand or implement an SPA well enough, and now your web thing is failing to serve users as well as it should, and using a multi-page architecture would have avoided the problems your website has now."

    • > Your arguments seem to be assuming a particularly bad implementation of a traditional backend.

      These weekly SPA complaint threads always assume a particularly bad implementation of a SPA as well though.

      4 replies →

    • Multi-page forms without some front end stuff ends up with the very clunky either "rerender previous form pages over and over again, except hidden", or "have some token to track partial form data", or "build up a DB to store a partially complete form".

      With some frontend work you can have a multi-page form just work, with the data stored in the client up until final submission, and only sending in partial checks ahead of time. This is qualitatively easier to handle, in my opinion.

      It also seems extremely uncontroversial that sending data for a single item is going to require less text generation than sending over that data + the entire page.

      These are all gradients, but people make absolute claims that don't hold up in these arguments.

      9 replies →

    • Most SaaS developers aren't serving APIs to their clients, they are serving websites and web applications.

      Applications have state. In order to render and deliver the application, the server needs to have some concept of what that state is.

    • > a bit of extra text

      Doesn't really sound like an application, but a website.

      In a web app it can happen that you use it for an hour without the backend doing a single thing.

      > There are only fewer languages to deal with if you aren't in charge of writing backend code.

      You don't have to deal with them at the same time

      6 replies →

  • > 1. You aren't mixing state across server and client. Single Source of Truth is a thing for a good reason. If you have a stateful backend, and your front end naturally has the state of whatever the user has input, you now have to work to keep those two in sync.

    If this were true, you wouldn't need a REST API. I don't understand what you're trying to say here. When you make a REST call to get data, you instantly have two different sets of state: the client and the server. It's no different from SSR, it's just transmitted in a different data format (json vs html).

    > 2. You need a beefier backend. A SPA backed by REST APIs is super easy to scale. nginx can serve up static resources (the JS bundle of the site) LOLWTF fast, and stateless REST apis are easy peasy to scale up to whatever load you want. Now you just have to worry about backend DB, which you have to worry about with non SPAs anyway.

    You do the exact same thing with SSR. Stateless shared nothing app tier instances. Been doing it for 15 years now.

    > 3. Less languages to deal with. If you are making a modern site you likely have JS on the front end, so with SPA you have JS + HTML. With another backend framework you now have JS+HTML+(Ruby|Python|PHP|C#|...), and that back end code now needs to generate HTML+JS. That is just all around more work.

    You can use JS on both the frontend and backend. Or ClojureScript. Or TypeScript. I'm sure there's others. But yes, for many languages this is a potential negative of SSR.

    • > If this were true, you wouldn't need a REST API. I don't understand what you're trying to say here. When you make a REST call to get data, you instantly have two different sets of state: the client and the server. It's no different from SSR, it's just transmitted in a different data format (json vs html).

      SSR means you don't have a clear representation of the client-side state (as distinct from the presentation) - by definition you render on the server and only serve the view layer to the client, whereas your data model only lives on the server. There will naturally be state in the client (e.g. form inputs), but you don't have a good representation of that in your model.

      > You do the exact same thing with SSR. Stateless shared nothing app tier instances. Been doing it for 15 years now.

      OK so where does the UI state live - not the long-term persistent entities, but things like unvalidated form input, which tab is enabled, which step of an in-progress wizard the user is on? Either you manage that on the client (at which point you're halfway to an SPA, and getting the worst of both worlds), or you manage it in the application layer on the server (in which case you have all the scaling issues), or you make every UI change go all the way into the data layer which has even bigger performance issues.

      4 replies →

    • Regarding a rest call (#1) being out of sync ... usually the "state" is in the database... if you're using SSR, it's still a separate context of state than what may be in the database a fraction of a second later.. and if you wish to keep that in sync, you're still going to need JS, or some other goofy hacks to do so.

  • > You aren't mixing state across server and client. Single Source of Truth is a thing for a good reason. If you have a stateful backend, and your front end naturally has the state of whatever the user has input, you now have to work to keep those two in sync.

    This is a bit weird to me, in that I'd say that cuts in the opposite direction. State can exist in at least three locations for most applications: db, app server, and client. Keeping state consistent across all of them can be difficult in the best of times, but thin clients by their very nature carry less state, lessening the burden. Sometimes client state is necessary, for richer user interactions, but for all but the most cosmetic of purposes you're going to have to replicate that state on the backend anyway, to enforce business and security requirements.

    • > but for all but the most cosmetic of purposes you're going to have to replicate that state on the backend anyway, to enforce business and security requirements.

      This really just comes down to what you're writing, how app-like your web app is. It's too easy to have one's own experience focused in a certain area and estimate the remaining majority as relatively similar. (For most of what I personally work on, the DB portion is mostly a simple straightforward serialization of what the user has built through the application; whereas client-side state has so many aspects to it I couldn't give a brief characterization—the whole app is basically client-side.)

      From what I can tell most of the disagreement about SPAs results from devs who are building things that aren't app-like railing against their futility vs devs who are, who become perplexed by the vitriol when they have immediate experience with their architectural benefits.

      6 replies →

  • This is missing the real reason that people write SPAs, which is that React solved web components, which are hugely beneficial for almost 100% of web sites, and thus became the standard for building web sites, and with React it's easier to make an "SPA" than to make a "traditional" site and users don't know or care either way.

    • Users care they just don’t know why many modern websites are bad websites. Every website is now an app whether that actually makes it better UX or not.

    • Web components actually aren't that good. Most seasoned and experienced developers I know hugely prefer either ASP.NET webforms or one of the many Java MVC implementations. We all know and use React daily, but I've literally seen the same application built faster with better maintainability and scalability once it was moved away from a SPA.

    • Also the React programming model is brilliant.

      Anyway the point is that people write SPA's because of React, not the other way around.

    • Wicket has offered a beautiful component approach for over a decade now. Having seen it I can't stand page-oriented MVC frameworks (indeed it's good enough that it convinced me that OO actually has some merit in some cases).

      4 replies →

  • I agree with all your points, but I think it's worth pointing out that those benefits you mentioned are largely for the developers. As a consumer I love a well-written SPA when the problem set calls for it, but most of the SPAs I have to use are garbage. I don't fault the tech for that, although I suspect that a lot of those SPAs were created by "me too" people that just wanted to build a SPA. When React was in the pre 1.0 days, I did that, and several people on my team as well (so I'm not casting any stones here, just trying to state facts).

    Last time I bootstrapped a React SPA I don't think cra includes a router ootb.

    • > but most of the SPAs I have to use are garbage

      As an example, look at reddit. I'm still using old.reddit.com because I can't stand their fancy SPA UI. It is so bad to the point, as a user, I enjoy a lot more HN's interface than reddit's one.

  • 2. Hard to believe that is true in the general case.

    Typical scenario for SPA is to use some sort of REST API, these API:s are usually designed for general usage, not specific usage, i.e. designed to be reused between components and views thus they basically return everything of a specific model regardless if data is needed or not.

    Therefore the controller queries the database with the equivalent of SELECT * on a table (or perhaps multiple tables with joins) and then exposes every field.

    And in many cases one request is not enough because the common generic design of REST APIs, thus a few request more are fired that results in multiple SELECT * against the database, and eventually the equivalent of SQL JOIN is performed in JavaScript.

    Already SPA solution has an increased cost by asking for data that is currently not needed, not only in the traffic between the database and the backend but also in the traffic between the backend and the frontend.

    And because we want to be good REST citizens we sprinkle the JSON payload with timestamps, resource urls and pagination information and what not and in majority of cases never to be used.

    Comparing that to SSR where you can fetch what you need from the database with custom SQL query (I hope you do, otherwise the SQL leprechaun will make a visit).

    Just imaging how much data there is on the web that is requested and then just discarded, not even looked at.

    It is possible to design custom REST endpoints for each component, but then of course what is the point of a SPA then? If you are already writing a custom REST endpoint just return HTML instead of JSON and then swap in the new and swap out the old for your component (one-liner), the end result is the same.

    SQL -> (Array of) object(s) -> JSON -> Javascript (Array of) object(s) -> HTML

    can therefore be shortened to

    SQL -> (Array of) object(s) -> HTML

    3. That doesn't make any sense, number of languages are still the same regardless.

    • GraphQL is such a quality of life upgrade coming from this environment, especially at the scale where your frontend teams are potentially larger and shipping more than the teams closer to the SQL can provide.

      24 replies →

  • > The majority of routers for React, and other SPA frameworks, do this out of the box. This has been a solved problem for half a decade at least. A website has to go out of its way to mess this up.

    They might not mess up history when using a standard routing library, but I've seen plenty of devs forget to add unique titles to different pages which is frustrating for a user with multiple tabs going.

    On SO the accepted answer for react-router looks like "create a custom Page component with title as a prop"[0]. At work I just ask folks to use react-helmet.

    [0] https://stackoverflow.com/questions/52447828/is-there-a-way-...

  • > . You aren't mixing state across server and client. Single Source of Truth is a thing for a good reason. If you have a stateful backend, and your front end naturally has the state of whatever the user has input, you now have to work to keep those two in sync.

    Why would I want to keep any state on the client? What in the history of the web (the whole idea being its someone elses computer) would make it a good idea to take away the one major selling point of the web? That no matter what, someone else has the state I need, and I never have to worry about losing that if something happens to my connection. It either went through or it didn't.

  • > The majority of routers for React, and other SPA frameworks, do this out of the box. This has been a solved problem for half a decade at least. A website has to go out of its way to mess this up.

    99% of SPAs break history related features in some way.

    • 99% of people don't FRICKING care.

      Most of the users I have to deal with still have problems with double clicking.

      They don't understand basic browser features.

      They don't understand that they can set preferred language in their browser.

      History related features are not an argument in any way.

      6 replies →

  • "A website has to go out of its way to mess this up."

    I know it's supposed to be easier, but I keep seeing teams mess this up.

    • I can say I've seen a lot of state management issues with SPAs... more with Angular than React, and almost none when using React+Redux well.

      I think a part of this is that a lot of developers simply don't desire, want to, get to or otherwise take the time to understand the framework they are using... It has been true forever... I can't tell you how many times I've seen stuff copy/pasted from StackOverflow, by devs that don't understand what they're doing, or they add jQuery to a React application, and have goofy interactions.

      The lack of understanding will always be a thing, you have to learn, most learn by doing, and when starting out, you don't know that what you are doing isn't good, but it kind-of works.

      4 replies →

    • I just don't know how it could be made any easier to not mess up. You really truly do need to go out of your way to mess it up, or be entirely unfamiliar with the JavaScript routing framework or library you're using.

    • They do, but it's usually the anti-SPA people who mess it up, by refusing to work with the grain of their tools. It's not quite the same thing as "strategic incompetence" but it feels related.

  • Client-side routing for page-oriented stuff is certainly not a solved problem: the basics, sure, but not actually doing it properly. There are some parts of the experience that it’s not possible to do perfectly because the web doesn’t expose the necessary primitives, and exceptionally few things go beyond the basics of just clobbering and resetting scroll position on back/forward. To do it properly, you need to restore all transient UI state (form field contents/state, scroll positions, focus, selection, media playback position; zoom level, probably not implementable; and there may be more, though I don’t include things like <details open> as transient state since that’s put into the DOM) on back/forwards, and I don’t know if I’ve seen anything actually do that. Then there’s the matter of helping accessibility tech to realise a page change has occurred, and I’m not sure of the state of the art on that, but last time I looked (some years ago) I think it was bogged down in unreliable heuristic land rather than actually being solved.

  • 1) JS history handling is fragile. A single error can break navigation completely. There's no built-in loading indicator so sites are left with no feedback or have bloated progress bars. And nothing automatically solves for deep links if the app doesn't use routes for different views or relies on other events instead of hyperlinks.

    2) Servers are very fast and assembling HTML is trivial. Browsers are optimized for downloading, parsing and rendering HTML as it streams in. Using JS to write HTML after making multiple network calls is objectively slower than a single network request that assembles everything on the server close to the datastore with minimal latency.

    3) Every other language is faster and more capable on the server than JS, and all major web frameworks have modern component-based UI templating. Interactions with roundtrips are just fine, and some light JS can handle most other scenarios.

    > "an actual application"

    That's the only reason to use a SPA, not what you mentioned.

  • All of your benefits seem to come from using only rest APIs to drive to site. That alone can be done with any site, but SPA usually implies more.

  • > SPAs are great for a number of reasons:

    > [...]

    > 2. You need a beefier backend.

    I don’t work on front-end and am trying to learn from this thread, so I may misunderstand, but that doesn’t look like an advantage to me. Doesn’t “beefier backend” imply “higher costs”?

Hi Simon, why'd you pull me in ;)

We recently went a rewrite of our frontend for https://www.crunchybridge.com from SPA to more "basic" request response app and couldn't be happier. Previously was SPA with React and we rebuilt from scratch with request/response using Node. In places we still leverage react components for re-usable frontend bits, but no more SPA and state management.

As you've mentioned in some of your other threads on this, the state management and sync between the API team and the front end team just caused velocity to slow down. It took longer to ship even the most basic things. While we want a clean and polished experience, the SPA approach didn't really accomplish any of that for us.

The rewrite was under 8 weeks of an app that had been built up over a couple years and we quickly recouped all that time in our new found velocity.

  • My knowledge is limited on the front end. May I know which Node framework do you use? Is it NextJS? If not, what do you think about using NextJS because I really consider it a better approach and want to use it at new projects.

Totally agree.

We built a product in ~5 months with real-time collaboration, extensive interactivity, Oauth, Stripe and Gmail integrations with a standard Ruby on Rails stack.

It's rock-solid, performant, dead-simple and extremely productive to work with.

Why're we throwing away years of learning to build unstable, complex and inaccessible applications?

  • >Why're we throwing away years of learning to build unstable, complex and inaccessible applications?

    1. Smart people seek out difficult problems.

    2. Difficult problems drive the creation of complex, niche tools, that bear cultural associations with the smart people who made and use them.

    3. People who want to be smart seek out complex, niche tools.

    • I think you're somewhat right, but it's not the whole story. There's another pipeline that goes something like:

      1. Technical software problems are more fun than difficult product problems

      2. Programmers would rather solve fun problems

      3. Programmers end up creating technically elaborate machines to solve simple (buy annoying) product problems

      2 replies →

    • I think it might be simpler?

      The more complex products are the only ones that typically have any documentation or up to date learning resources.

      You want to learn how to build a thing and this is the only thing that really exists, is up to date, and works.

      It may not be the right tool, but for someone new it's impossible to tell what the right tool is and people online are stereotypically obtuse and about anything tool related.

    • lmao yeah pretty much. I'm moving from a low code shop to Node/Vue because I can't keep people. They all want to pad their resume, so I'm going to build at 2x the cost just so I can keep the projects going.

      1 reply →

    • Smart and YOUNG, seek and try to conquer complexity, pushing open The Gate of Truth. Only to be completely consumed and burned by it.

      There are abundance of smart people. Wisdom, has and possibly always will be in short supply.

      2 replies →

  • Same experience here, in our case with Laravel. The project started as a Next.js SPA and after we needed to add authentication, translations and background jobs things became so crazy and so "custom" that we ditched it and in almost 2 weeks had everything built in a much more robust way with Laravel and Livewire + Alpine.

  • Because the majority of developers will gravitate towards tools that will give them the best employment opportunity, not necessarily the best tools for the job.

    TL;DR Resume Driven Development

  • What approach did you take with real-time collaboration and interactivity? Is that part still rendered client-side?

  • One could argue rails is just doing a decent job of hiding a monstrous amount of unnecessary complexity from you for basic CRUD stuff. It’s good at this… until it isn’t. In the the whole ORM abstraction (not just in rails) is questionable.

    The way most of us would handle authorization in something like rails is a leaky abstraction, especially when we’re usually backing onto postgresql which has very mature roles and permissions.

I always thought of the benefits of SPAs more as a separation-of-concerns thing. You can pretty effectively build a functional front-end web application and mock a set of back-end REST apis, while another team builds out a the back-end. There are absolutely tradeoffs, and being a good software engineer is about understanding where and when those tradeoffs apply.

  • That's definitely true at the organizational level, and it's an argument with some merits.

    In practice though, I've seen this backfire. You end up with the frontend team blocked because the API they need isn't available yet, and then the backend team gets blocked because they shipped the API but they can't use it to deliver value because the frontend team don't have the capacity to build the interface for it!

    My preference is to work on mixed-skll teams that can ship a feature independently of any other team. I really like the way Basecamp describe this in their handbook: https://github.com/basecamp/handbook/blob/master/how-we-work... - "In self-sufficient, independent teams".

    • that sounds like a mismatch between the architecture and how work is getting planned no? if the backend is in the critical path to delivering the user value of a feature then the backend and frontend engineers need to be developing (and testing) the feature together

      1 reply →

  • That's not really unique to SPAs, right?

    I don't know much about front-end development but I imagine you can create a front-end that is both not an SPA, and not server-rendered.

    • It's not about being unique, or what you can/can't do. You certainly can mock a front end with a ssr app, but it gets messy when you are building a rich client app and need to start sharing state back and forth.

  • You can still do that with SSR solution, the mocking just moves one step down, instead of mocking a JSON request you mock a class or an interface.

When SPA started picking up steam, I thought it was an amazing development! We had gone from mainframes, to personal computers, and were back to mainframes and using our powerful machines as glorified dumb terminals. This way, we could have UI code running locally, and servers only handling state. Plus, less data to transfer!

Then the frameworks ballooned in size. What previously was seen as wasteful (rendering and sending HTML) started to seem pretty frugal in comparison to the multi megabyte pages. Not to mention that one could always send just page fragments.

Other than specialized apps, I think most single page applications are a mistake. Sure, some may benefit from a nice UI - say, I'm writing a 3D modeler. But most apps there are could just re-render pages. 'Refresh' is not much of a problem in an age where simple REST API calls are returning megabytes of JSON data...

I try to tell myself "don't get caught up in using a fancy frontend framework on this one," as I'm starting a new project, but I keep running into situations where my functionality would just work so much better.

As an example, I was writing a tool the other day to automate some things that have to do with quotes for my 9-to-5. Being able to add inline functionality in Django to select a customer within the quote page, or add / edit a new customer without having to leave that quote felt very 'hackish,' using the same jquery callback method used in Django Admin. My point is, this feels like very basic functionality, but turned into a whole other ordeal using traditional methods.

  • > Being able to add inline functionality in Django to select a customer within the quote page, or add / edit a new customer without having to leave that quote felt very 'hackish,' using the same jquery callback method used in Django Admin.

    Agreed. For form based apps I don't like to fall back to SPAs (bloat, the desire of every dev to reinvent forms in their framework, client and server side validation duplication), and yet working with relational data they are easier.

    It's one of those places where a half-way step would be so useful.

    • That is something I hadn't really taken the time to compartmentalize and articulate, but a js framework that focused on forms only would be wonderful. I'm sure that someone has taken a stab at it. Something like crispy-forms that added the ability to add components for variable data such as inlines...

      I'm guessing that Vue.js may be a good drop-in for this, but it has been a while since I have used Vue.

I initially thought part of the appeal was offloading the workload to the front end, where your processing power scales infinitely with each user's device. Maybe the benefit turned out to be negligible, I'm not really sure. Can server costs be reduced by offloading the work to the front end?

  • They absolutely can, if your workload is ideal for this situation, but unfortunately, the most "expensive" (in terms of time, money, computing power, you name it) part of giving a user information is typically the filtering and collation of that information from a much larger pool of information — almost always a pool of information that is far too big and too private to just send to the client to sort through locally.

    Even in the most simple scenarios, you quickly find your limits. If you get data back, but it's paginated (and it almost always has to be, for basic reliability reasons as much as anything else), you can't be guaranteed to have the complete set of data in a given circumstance, so you can't perform operations like filtering, pivoting, or sorting that data locally. You have to ask the server to do this for you and wait for the response, just like we've had to in the past.

    • Dynamic loading of content is a feature of SPAs, but it's not a defining feature, nor unique. In fact, one defining feature of SPAs is the offline capabilities (service workers, caching, etc.), which sits at a bit of a tangent to database considerations like this.

  • If you can actually offload substantial CPU cycles to the client, yes, you'll save server costs. But the SPA hype has led to a lot of SPAs that work like this:

    > User clicks a tab. A request to server fetches the JSON data for the tab. Client renders it to HTML. User fills in some fields and clicks submit. A request to server sends the JSON form data and gets a JSON response code. Client shows a confirmation screen. ...

    In this case, you're not saving much by templating JSON on the server instead of just templating HTML.

  • This was one of the appeals initially, and would certainly still be true if you were doing something very processor intensive that could securely be done on the client.

    Languages/runtimes have gotten faster and more optimized, while hardware has continued to move forward. It's also far easier now to add more backend instances using orchestrators like k8s, so it's less of a big deal to have to add replicas.

  • > Can server costs be reduced by offloading the work to the front end?

    I would say yes. One significant benefit of SPAs is that you can produce fairly complex applications without any server logic, only static hosting. The workload is essentially offloaded to the build process and the front-end. You still need to carefully consider the effect on e.g low powered and js-disabled devices ... but these are straightforward considerations.

>Not only do we not seem to be learning from our mistakes

That is a lot of good faith. What happens if they were not mistakes? But deliberate attempt to push Javascript as the one and only de facto approach to web development and Resume Driven Development?

I recently asked this [1],

I dont want to name names, but do any tech company actually apologise after their high evangelism to the world and industry and walk back 70% of their decision five years later?

And for some strange reason this mostly happens to Web Development in general.

[1] https://news.ycombinator.com/item?id=30451916

I know people for whom the traditional way of building a web app is completely foreign. I am curious how you would describe the concept and tools to someone who has never encountered them before outside an SPA architecture.

>....taking advantage of the supposed benefits of SPAs: there are no snazzy animations between states....

If that's the main benefit, let's hear it for MPAs. I want a website that's fast, responsive, clicky, sharp and to the point - not some soft-focus pastel cartoon movie. As the author says, that's fine for audio/video sites (and reasonable for other entertainment-focussed sites) - for information sites it just gets in the way (animated elements - especially persistent ones - are a terrible idea when trying to concentrate on textual content).

  • > not some soft-focus pastel cartoon movie.

    For some reason, designers likes it no matter it makes sense or not, so it is what you get. The current designer trending is just a shit show, nuke the usability for nearly no benefits IMO.

It’s all about state management IMO. There are legitimate reasons to keep UI specific complex temporary state on the client that would be more complex (and slower) if the server needed to hold it. So an SPA or at least partial SPA in some situations does makes sense.

But it does tend to become a hammer for every screw over time…

> It's been so frustrating watch this play out over the past decade.

> I keep seeing projects that could have been written as a traditional multi-page application pick a SPA architecture instead, with the result that they take 2-5 times longer to build and produce an end-result that's far slower to load and much more prone to bugs.*

Its been frustrating seeing the webplatform not play out, seeing so little growing in to SPAs, so little maturing.

Url-based routing is heavily under-represented, tackes on only by the one or two blokes who happened to have some memory of web architecture. This clairifies the architecture both internally & externally.

As bad a problem, single page apps being stuck, forever, at single-bundle apps is phenomenally sad. Splitting bundles into chunks as a manual development task is so hard, so bad. The goal of having web based modules almost made sense, almost happened, but we rafically underinvested in transport technology, cache-digest going undelivered. I continue to think js modules, with import maps- the key tech to making modules modular- is worth it, would help make our architecture so much better. There is mild extra time to first load, but worth it/small, & cached after.

Again we're damned though. Years too late to try & see how excellent it would be to have something like react cached & AOT compiled as from a cdn. Because now privacy concern freak-outs mean this huge advantage of only needing to pull & potentially compile a js module once are gone: site-partitioning rules. We could have had better architecture, been using the language not absurd bundlers, and enjoyed high cache bit rates for common libraries. SPAs just didnt care, never tried at all, we all (almost all) did a horrible job & took way way too long (over a decade) to make modules modular g usable. There was so much hope g promise & such abaurd non-delivery, on the module front, on app archtiecture.

HTTP3 and early-hints still have some promising hopes for accelerating our transports, making "just modules" a possibility & fast, without careful hand optimization. We could still do more to optimize bundles, have automated tools that analyze up front versus on-demand dependency bundles, build http bundles of these. But i hope eventually itcs mostly not super necessary to build webpackage (nor far worse, webpack) bundles.

SPAs still have great potential. More so, now that we finally have some support tech for modules forming.

I mean, of course the co-creator of Django would say this.

I wouldn't recommend newer generation of developers to build traditional web apps, let alone use jQuery.

I don't understand why people think we're still in the age of form submissions and blog posts - There has to be a good majority of us here that has worked on something complex that required SPAs here, no?

Not only would it be detrimental to a young developer's career to suggest avoiding SPAs in regards to hiring, but only limiting that developer to create blog post styled content is severely restraining.

Let them develop their blogs in SPAs, at least when they are needed to go into something a bit more complex, they at least have the foundational knowledge required to move towards that.

What you're suggesting is to learn two things, (one that is inevitably being phased out), and spend the mental effort to discern when to use either one, when the more beneficial alternative is to learn SPAs and just go with it.

No 18-25 year old is trying to make a Weblog where walls of text is the main content - Youtube shorts, instagram reels, tiktoks and all these bite sized content has done a great job at destroying that level of attention span.

They're going to be building something else, something quick and visual, something pleasing to the eyes - and more often than not, it's going to require a SPA.

  • > I don't understand why people think we're still in the age of form submissions and blog posts

    Because we are.

    > There has to be a good majority of us here that has worked on something complex that required SPAs here, no?

    No. Because complex stuff doesn't require SPAs.

  • > There has to be a good majority of us here that has worked on something complex that required SPAs here, no?

    You can still create a something complex without using any of the common SPA techniques, instead you can use things like Hotwire, Livewire, htmx instead.

    • not practical for hiring.

      and although I find it intriguing that hey.com is using Hotwire, it's still insignificant compared to some SPA framework's ecosystems.

      Performance isn't an end all be all, otherwise we should make another article and say "Python and PHP was a mistake for web servers"

      There is some give to be had for the sake of practicality.

      1 reply →

I really view it as the opposite.

Prefer the writing of an SPA or serverless MPA.

If you consider that native desktop and mobile applications are siloed applications that coordinate with an API to achieve tasks - this is basically how SPAs or serverless MPAs work.

Part of the reason this is effective is because of the low cost nature of deploying applications like this.

For example; I can write a calorie counter that stores records in the client via indexeddb.

Given all the work is processed on the client, using an http server would be an unnecessary maintenance burden as it would simply server static files.

Rather than host the web application via a self managed http-server, I can just put my html files on S3 making hosting it free and unmanaged.

Should I decide I need to add user accounts and cloud storage - well I can then create a backend that exposes API endpoints to facilitate the tasks.

Those endpoints are then compatible with native applications, should I decide to write native mobile and desktop variations of my web application.

Furthermore, with Web Assembly expanding to offer the ability to write web applications using languages like C++, Rust, C#, Golang and the browser expanding access to OS subsystems like filesystem access - what we are seeing is that the browser is becoming a sandboxed UI toolkit, much like GTK or QT (except without native styling).

If there was anything that would empower Linux Desktops to be compatible with productivity software - it's progressive web applications.

Consider that Photoshop and Office are accessible on Linux via web today.

  • That's a lot of interfaces to create and maintain. The principle value of backend/MPA frameworks like Rails & Django is that they give you nearly all these interfaces for free in a neat package, which ends up being "good enough" for many use cases below Google-scale.

  • A calorie counter using IndexDB is a great example of something where an SPA is appropriate - like I said, "default to not writing an SPA, unless your project has specific, well understood requirements (e.g. you're building Figma) that make the SPA route a better fit".

    I mainly work in the world of database-backed websites and applications, where going client-only without a backend isn't an option.

  • > Consider that Photoshop and Office are accessible on Linux via web today.

    Never used Photoshop, but Office on the web still sucks compared even to native MS Office.

  • You're describing an actual client side (mobile or desktop) application made with web technology, not a web application. That's a fair use of SPA tech.

    As soon as you need authentication, showing data across users, allowing visitors to see shared data, perform validation of inputs, send notifications when other user action happens, etc you're back in SPA hell.

    • Why do any of those attributes put you in SPA hell?

      If you were to write an Android application that featured Authentication, would you also be in "app development hell"?

      Languages, performance and UI decorations aside - it's basically the same thing, no?

>e.g. you're building Figma

i think what it comes down to is if you have to make a decision of "should i build an SPA?" the answer is no. the web is good at doing pages. if your app has pages, use the web's default page mechanism.

and i don't say this as a hater of single-page apps. i love webapps, and i think that building a webapp should be the default for most cases. there's a lot of apps that don't naturally break into a "page" metaphor, and all the technologies that are part of the single-page app concept are great for those cases.

figma is a perfect example, because there's no obvious division between what would be one page versus another. it's not a paginated website that has been built as an SPA, it's literally just one page that has a whole bunch of interactivity.

Don't don't do what I would do. The mistake is forgetting first principles. You don't do something good by focusing on what not to do (like don't be evil). Focus on what to do: KISS, YAGNI, etc.. even DRY is a far lower priority. Software, especially frontend and web are rampant with problems from operating as an echo chamber. Just consider what Ryan did with Deno and had to say criticizing his first project. Yet folks are still wildly supportive of the older technical decisions and go to great lengths to preserve those same mistakes.

Idk I don't think the problem is the SPA itself, it's bad design patterns that that make it terrible as you say.

I think really clean, performant SPAs can definitely be written and I think the overall experience of using a SPA can be much better than a multi-page site if the task at hand requires it.

There should be two parts of the web now really: * Traditional multi-page websites * SPAs that could have been a native app on the device, but are much more accessible in web form and without requiring an install

  • The alternative to SPAs is not 90s pages reloads. Nowadays you have livewire, hotwire, unpoly, htmx and several other modern solutions.

Speaking for myself, I find it much quicker and easier to build an SPA than a server rendered app. You seem to take the stance that server rendered is the default, normal way to architect and SPA requires justification for its aberrant departure from the norm.

SPA have lots of advantages: fewer languages to learn, easier to deploy, etc.

  • > SPA have lots of advantages: fewer languages to learn, easier to deploy, etc.

    The two examples you give are only true if you don't have a backend at all. As soon as you have a backend, you're back to having to pick a backend language and deploy a backend server.

    If your app doesn't need a backend, then I'd agree that an SPA is the way to go.

Example wealthfront.

All pages are SPAs. I mean, page A is SPA, page B is another SPA and page C is another SPA.