I basically exclusively write SPAs and they are way, way harder than MPAs to keep straight due to state behaviour and the mountain of JS.
Additionally, component-first designs are frankly often NOT what is wanted by your product and design team. What they want is to easily update how the page looks, and a lot of the time that is factually way easier with a template-first approach.
There exists a gray area, but SPA by default is ludicrous. Please consider what you are trading off if you do this, because it's often not worth it and I'm tired of having to argue such an obvious point everywhere I work.
From what I've observed, SPAs will never close the performance gap with a MPA server-rendered page. Even if you could, the effort required would not be worth it.
I can sympathize with the “mountain of JS” but SPAs way easier to reason about in abstract. In SPA world there’s an API server which is self-contained and has clear boundaries — take JSON payload ish and return JSON payload ish. Server has no knowledge or connection to any client.
Client is a static bundle of JS and assets which just calls the API just like our iOS/Android/CLI.
Once you involve SSR (beyond hydration) you’re in for a world of hurt because you’re mixing the two. The JS doesn’t know about the HTML despite them hard depending on one another and the two processes can’t communicate back and forth anymore. Both sides are disconnected but have shared state because half of the client is actually on the server. Way more complicated than every half keeping its own books without any care. If it weren’t for “it’s what we had to do back then” it would be considered nuts to codegen whole applications and then send them across the network to run but that’s SSR.
> In SPA world there’s an API server which is self-contained and has clear boundaries — take JSON payload ish and return JSON payload ish.
In theory yes, in practice I’ve more often than not seen the same team build both client and API meaning they’ve just added a bunch of operational complexity without having anything to show for it.
In my opinion the reasoning why "SPAs [are] way easier to reason about in the abstract" is neglecting to acknowledge that most applications evolve over time.
There is no well-defined API on the server side. The application logic is smeared across code the runs in the browser and code that runs on a server. That "API" is usually merely an HTTP endpoint that connects both sides. Adding new functionality to the application requires touching both sides, and changing the HTTP endpoint. I would use different approaches to build those HTTP endpoints and to build a "proper" API that's used by different consumers.
> From what I've observed, SPAs will never close the performance gap with a MPA server-rendered page. Even if you could, the effort required would not be worth it.
It feels like the performance was one of the key selling points of stuff like Gatsby, but in reality it scored absymaly on all metrics compared to a vanilla WordPress installation on a $5 DO droplet.
With the same computer spec, serving file via HTTP (gatsby) is cheaper - or at least wont scale parallel to complexity - compared to WordPress which build the page at request-time, unless I'm not up to date with how WordPress is rendered right now.
Can you clarify a bit what you mean with the component-first design part? In my experience, working with components is a significant force-multiplier in terms of being able to encapsulate behaviour within an application, but I'm intrigued what you see as difficult here.
It's only a force multiplier if your Design team sticks to it to the letter, and also if you are able to upkeep the components and refactor them nicely and often.
What you more often get are requests to redo one page with a newer design and go from there. Well, the overhead for that is now massive, because all the components need to be refactored to allow customizable style, or you need to build new replacement components for pages to opt into, then redo the pages with all these new components slotted into a new layout.
...and all they wanted was to change the borders, input field appearance, colors and try to make the existing table more responsive.
In other words, they are (probably?) hoping that the page has something like one giant data object / hook that is 100 percent separate from the UI, where you can just screw with the style sheet and the markup to try some things out quickly and call it a day.
In a component design you have to think carefully about what gets data from where, but this is something the non-tech folks at an org just don't give a shit about, and they expected you to just be able to tweak the page.
So, to me the optimal technical approach is page template first, maturing into component re-use second. And I would suggest you decide carefully what to make into components when nobody has formally asked you to do so, because:
1. The overhead of arguing about time required to refactor/rebuild components is absolutely real. The point of components is that you shouldn't build snowflakes, yet that is what is routinely wanted.
2. Scope of "simple" component changes potentially touch the whole app when you'd rather it - or morely need it to - NOT.
Thank you, that's a very interesting response, and also the complete opposite of my experience with this sort of thing!
In my experience, the design team is often even more component-driven than the dev team, with more interest in things right down to things like design tokens to specify consistent line widths. Whereas developers also use components to encapsulate design, but mainly use it to encapsulate behaviour or local state - say, a drop-down that needs a particular search functionality, or a breadcrumb component that needs to update as the page history changes.
Maybe you are just working with better designers than I have!
I find they all care about these things, but either their imagination or direction from above gets the best of them and it ruins the party.
Then you are left with change requests that don't fit with the existing design system - a bunch Lego blocks with nobody that wants to play with them anymore.
I would say - on good days - my experience matches yours. On the other days... you are basically being asked to rewrite entire pages to conduct experiments. At that point I have to ask - is the Design request unreasonable, or did we make the wrong decision and prematurely optimize for components instead of just sticking with a more malleable template?
SPA usually consists of bulky js files if not utilizing lazy-loading correctly. The size makes it slow.
But, I think this thread is conflating SPA vs MPA and compile-time vs request-time "rendering".
With the same complexity, compile-time rendering should be faster than request-time rendering. But in reality, most compile-time rendering is also SPA.
There are also other factors such as server's performance and cache utilization which people often forget when talking about this topic
> Indeed, we've started to notice that many newer developers aren't even aware of an alternative approach, as they've spent their entire career in a framework like React
This is exactly why it's often best to use React even if it's overkill. It makes recruiting and onboarding new devs to the codebase much easier. Given the rate of turnover for frontend devs, this is a significant advantage.
This is a tough stance for me to get on board with. You're not wrong to value SPAs for this reason, but I don't think picking the wrong architecture on purpose is defensible either.
There are no panaceas in technology stacks, but it does shock me sometimes how teams blindly jump to React (and sometimes Next) just due to perceived popularity and don't actually do any analysis on what their problem points are, and whether it would make sense for them.
A few months ago (around the Christmas break) I decided to build a web UI for something. The last time I personally touched “front end” HTML or JS was when IE5 was a thing, although I’ve done a lot with server side TypeScript and the Node ecosystem.
I spent a couple of days evaluating the options, coming at this with fresh eyes, but not as a beginner to programming or architecture, and found the following:
- Ember makes the most sense to me personally, but at the time the stable ember packages pulled in several dependencies npm called out as vulnerable, and editor support was not great. The webstorm plug-in basically didn’t do anything useful. Finally, it was not obvious that TypeScript was a first class citizen, which put me off.
- Vue seemed ok, if a little harder to reason about than Ember - I can see why people like it but there didn’t seem to be a compelling reason to put effort into it.
- React is hands down the “winner” of the ecosystem, is easy to get up and running with and has great editor support. As someone that generally likes functional programming, the concepts clicked nicely. TypeScript was first class, TSX seems nice enough.
In the end, the limited time I had meant I just wrote a native Mac app with SwiftUI, and resolved not to touch web stuff for another 2 decades if I could avoid it.
I have a huge amount of respect for people who can keep the front end web ecosystem straight in their head - I really don’t understand why people consider “back end” the more complex technical domain.
Svelte is still the better choice. It compiles to much better optimized and smaller bundles, and a team of React devs can learn Svelte in a weekend thanks to how much leaner and more intuitive it is, as well as how true it stays to writing vanilla JS/HTML/CSS. The huge gains in dev speed and ability to plug and play any vanilla library without a framework wrapper make it hard to justify React over Svelte.
A slight tangent, but it also seems that the progressive web application (PWA) technique, although briefly recommended[1] for "trial" has been removed from the radar.
Almost everything gets "removed" from the radar every six months. The Thoughtworks radar is published twice a year, and each volume of it only contains what Thoughtworks found new and noteworthy in the six months leading up to the publication of a volume. There's more in the FAQ: https://www.thoughtworks.com/radar/faq-and-more
I basically exclusively write SPAs and they are way, way harder than MPAs to keep straight due to state behaviour and the mountain of JS.
Additionally, component-first designs are frankly often NOT what is wanted by your product and design team. What they want is to easily update how the page looks, and a lot of the time that is factually way easier with a template-first approach.
There exists a gray area, but SPA by default is ludicrous. Please consider what you are trading off if you do this, because it's often not worth it and I'm tired of having to argue such an obvious point everywhere I work.
From what I've observed, SPAs will never close the performance gap with a MPA server-rendered page. Even if you could, the effort required would not be worth it.