63 comments

[ 2.4 ms ] story [ 70.3 ms ] thread
"Now’s a good time to figure out whether your client-side application should have a server-side aspect to it, to speed up initial renders."

My how the tables have turned!

> I’ll focus on React and Redux in some of my examples since that is what I have the most experience with, but much of this applies to other frameworks and to JS-heavy approaches in general.

That's not a fair assumption. Frameworks like Svelte, Solid, Vue etc have smaller bundle sizes and rendering speeds that approach the baseline vanilla-js cost.

I'm all for criticising Javascript, but moving everything to the server isn't a real solution either. Instead of slow React renders (50ms?), every interaction is a client-server round trip. The user pays the cost of the paradigm on each interaction instead of upfront with an initial JS payload. Etc.

Yeah this article is only about React. But it makes sense that someone would think this way because many dev's think JS web apps==react only.

The problem is react is "good enough" for most cases and the performance degradations happen slow enough that the devs/project leads don't see it until it's too late and they are already overly invested in there project and switching would be too compliated/costly for them.

Svelte/kit and properly optimized packages solve almost all of the "problems" this article tries to bring up.

> Instead of slow React renders (50ms?), every interaction is a client-server round trip.

This is true only if you use zero javascript, which isn't what the article is advocating for (and even with zero javascript there's quite a bit of client-side interactivity built-in to CSS and HTML). Besides: in practice most interactions in an SPA also involve network round trips, in addition to that slow react render.

In other news: water is wet. I genuinely don't understand how anyone is still pretending otherwise. Server-side rendering is so much easier to deliver in a performant way, yet it feels like it's being increasingly forgotten — or worse, actively dismissed as outdated. Out of convenience, more and more developers keep pushing logic and rendering onto the client, as if the browser were an infinitely capable runtime. The result is exactly what this article describes: bloated bundles, fragile performance, and an endless cycle of optimization that never quite sticks.
Pure client side rendering is the only way to get max speed with lowest latency possible. With ssr you always have bigger payloads or double network rounds.
Server rendered HTML, htmlf endpoints and JQuery load was always the sweet spot for me - McMaster Carr[0] does the same thing behind the scenes and utterly destroys every "modern" webapp in existence today. Why did everything have to become so hard?

0: https://www.mcmaster.com/

A cogent article. But I think the biggest problem is that the DOM was built for documents, not apps. We know how to build a performant UI architecture: Qt, Java/Swing, Cocoa all have pretty similar architectures and they all ran fine on much poorer hardware than a modern browser on an M1. But unless you use WebAssembly, you can't actually use them on the browser.

When the industry shoehorns something into a tool designed for something else, yeah, performance suffers and you get a lot of framework churn with people trying to figure out how to elegantly cut steaks with spoons.

But most apps are documents, they are built to render data and text fields in a nice way for the consumer to use.

You most certainly shouldn't be building graphs with table elements but JS has canvas and svg which make vectors pretty efficient to render.

The document model provides good accessibility and the ability for things like SEO and GEO to exist.

If you are making a racing simulator, then using HTML in no way makes sense, but for the apps that most of us use documents make sense.

It would be nice if browsers implemented a new interpreted statically typed language with direct canvas/viewport rendering that was more efficient than javascript, but chrome would need to adopt it, then developers would need to actually build things with it. It seems like it would currently have to come from within the chrome team directly and they are the only ones that can control something like this.

> the biggest problem is that the DOM was built for documents, not apps

I don't see the difference. They're both text and graphics laid out in a variable-sized nested containers.

And apps today make use all the same fancy stuff documents do. Fonts, vector icons, graphics, rounded corners, multilingual text including RTL, drop shadows, layers, transparency, and so forth.

Maybe you think they shouldn't. But they do. Of all the problems with apps in web pages, the DOM feels like the least of it.

> Java/Swing

> performant UI architecture

Not sure if it’s a joke or something.

You can easily prove if the DOM is a performance bottleneck. DOM performance means one of two things: lookup/access speed and render speed. Render speed is only a DOM concern with regard to quantity of nodes and node layering though, as the visual painting to display is a GPU concern.

To test DOM access speed simply compare processing speed during test automation of a large single page app with all DOM references cached to variables versus the same application with no such caching. I have done this and there is a performance difference, but that performance difference cannot be noticed until other areas of the application are very well optimized for performance.

I have also tested performance of node layering and it’s also not what most people think. To do this I used an application that was like desktop UI with many windows that can dragged around each with their own internal content. I found things slowed down considerably when the page had over 10000 nodes displayed across a hundred or so windows. I found this was slower than equivalent desktop environments outside the browser, but not by much.

Most people seem to form unmeasured opinions of DOM performance that do not hold up under tests. Likewise they also fail to optimize when they have the opportunity to do so. In many cases there is active hostility against optimizations that challenge a favorite framework or code pattern.

> I think the biggest problem is that the DOM was built for documents, not apps.

The world wide web was invented in 1989, Javascript was released in 1995, and the term "web application" was coined in 1999. In other words: the web has been an application platform for most of its existence. It's wrong to say at this point that any part of it was primarily designed to serve documents, unless you completely ignore all of the design work that has happened for the past 25 years.

Now, whether it was designed well is another issue...

Only a single passing mention of web components?
> You can use isolated JS scripts, or other approaches like progressively-enhanced web components

How would one use "progressively enchanced" web components? Maybe I misunderstand the intention behind this statement, but web components are either supported or not. There doesn't seem to be some kind of progression.

(comment deleted)
Eh, this argument falls apart for many reasons:

- His main example of bloated client-side dependencies is moment.js, which has been deprecated for five years in favor of smaller libraries and native APIs, and whose principal functionality (the manipulation and display of the user's date/time) isn't possible on the server anyway.

- There's an underlying assumption that server-side code is inherently good, performant, and well crafted. There are footguns in every single language and framework and library ever (he works for WordPress, he should know).

- He's right to point out the pain of React memoization, but the Compiler now does this for you and better than you ever could manually

- Larger bundle sizes are unfortunate, but they're not the main cause of performance issues. That'd be images and video sizes, especially if poorly optimized, which easily and immediately dwarf bundle downloads; and slow database queries, which affect server-side code just as much as browser-side code.

> There's an underlying assumption that server-side code is inherently good, performant, and well crafted

To me it’s an assumption that server side code is going to be running on a server. Which is a known quantity and can be profiled to the nth degree. It’s extremely difficult to profile every possible device your site will run on, which is crucial with low powered mobile devices.

> Larger bundle sizes are unfortunate, but they're not the main cause of performance issues. That'd be images and video sizes

Not really, no. Large bundle sizes prevent the initialisation of the app, which means the user can’t do anything. By comparison images and videos download asynchronously and get processed on a separate thread. JS bundles also need to be parsed after being downloaded, if you pair a crappy Android phone with an 5G connection the parsing can literally take longer than the download.

> Larger bundle sizes are unfortunate, but they're not the main cause of performance issues. That'd be images and video sizes, especially if poorly optimized, which easily and immediately dwarf bundle downloads; and slow database queries, which affect server-side code just as much as browser-side code.

In network terms JS tends to be downloaded at a higher priority than both images and video so has a larger impact on content appearing

JS is also the primary main thread blocker for most apps / pages… profile any NextJS app and you’ll see what a horrendous impact NextJS has on the main thread and the visitor’s experience

> There's an underlying assumption that server-side code is inherently good, performant, and well crafted.

I didn't read it that way. I believe the underlying assumption is that the server-side code won't run in a power-constrained computer, thus having more performance headroom.

I’m still baffled why this language is the universal browser standard. There should be hundreds competing.
I am so grateful to the author for writing this article. For years I've been fighting a series of small battles with my peers who seem hell-bent on "upgrading" our e-commerce websites by rewriting them in React or another modern framework.

I've held the line, firm in my belief that there is truly no compelling reason for a shopping website to be turned into an SPA.

It's been difficult at times. The hype of new and shiny tools is real. Like the article mentions, a lot of devs don't even know that there is another way to build things for the web. They don't understand that it's not normal to push megabytes of JavaScript to users' browsers, or that displaying some text on a page doesn't have to start with `<React><App/></React>`.

That's terrifying to me.

Articles like this give me hope that no, I'm not losing my mind. Once the current framework fads eventually die out - as they always do - the core web technologies will remain.

I think shopping gets this in spades too because not all shopping sites are meant to be particularly sticky.

It's one thing to browse the catalog at my leisure on gigabit networking, a 5k display and 16 CPU cores. It's another thing when I'm standing in Macy's or Home Depot and they don't quite have the thing I thought they have and I'm on my phone trying to figure out if I can drive half a mile to your store and get it. If you want to poach that sale your site better be fast, rather than sticky.

he links to infrequently.org a few times in the article. You should read every article there - its a revelation.

Then check out Datastar

Github was usable and fast, now it is slow. Guess what changed...
It was re-written in React and performance was annihilated. The React Virus annexed another victim and we have one more zombie web-site.
It's crazy slow. But it's also a closed source, Microsoft platform for Open Source, so it belongs in the trash anyway.
Acquisitionbombed by Microsoft! Instead of usability and performance it has AI now!
This title is very misleading, it should be "Why React is not compatible with long-term performance goals"

And I do agree generally. React uses an outdated rendering method that has now been surpassed by many better frameworks. Svelte/Sveltekit, Vue, and Qwik are the best examples.

People relying on bloated React packages is obviously not great but that is nothing to do with javascript itself.

The JS engines are all relatively fast now. And the document model of the current web provides major accessibility to both humans and search tools like SEO and GEO. JS is not my favorite language. I would rather the web was based on a statically typed language that had better error handling practices like Go. But this will most likely not happen any time soon as it would require every level of the ecosystem to adapt. Browsers, Frameworks, Developers etc.

Google would have to take the lead and implement this in chrome then enough developers would have to build sites using it and force safari and firefox to comply. It just isn't feasible.

If you want faster webapps just switch to sveltekit or vue or qwik. But often the ones choosing the framework for the project have not written much code in years, they know react is as safe option and used by everyone else so they follow along, if it gets slow its a "bug" causing it as they built apps that were "good enough" before using it.

> I would rather the web was based on a statically typed language that had better error handling practices like Go.

So, dart?

Back in the day Google had plans to make a dart VM in Chrome, but powers that be didn't like this idea.

So here we are. it's 2026 and the web is still limited to one language. Dare I say the only area where we don't have alternatives.

> People relying on bloated React packages is obviously not great but that is nothing to do with javascript itself.

JS is slow. If React was written in C++, the performance wouldn't be an issue. Then again, React is trying to solve DOM issues, not JS issues.

I was never a big React fan myself. As someone who has used a lot of different JavaScript frameworks over many years, I can say confidently that it's not the best JS framework; especially nowadays due to bloat.

Yet it's better than anything available in any other programming language, on any other platform in existence.

Never bet against JavaScript. People have done this over and over and over again since it was invented. So many haters. It's like every junior dev was born a JavaScript hater and spends most of their career slowly working themselves to a state of 'tolerating JavaScript'.

JS was designed to be future-proof and it kept improving over the years; what happened is it improved much faster than people were able to adjust their emotions about it... These people even preached the JS hate to a whole generation of juniors; some of whom never even experienced JavaScript first-hand. It's been cool to hate JavaScript since I can remember.

JavaScript does have some bad parts, as does any other programming language, but the good parts of JS are better than anything else in existence. People keep trying to build abstractions on top (e.g. TypeScript) to try to distance people from JavaScript, but they keep coming back over and over again... And these people will never admit to themselves that maybe the reason they keep coming back to JavaScript is because it's pretty darn great. Not perfect, but great nonetheless.

It's hilarious that now we have Web Assembly; meaning you can compile any language to run in the browser... But almost nobody is doing that. Do people realize how much work was required to bring Web Assembly to the browser? Everyone knows it exists, it's there for you to use, but nobody is using it! What does that say? Oh, it's because of the bundle size? Common! Look at React, React bundles are so bloated! But they are heavily used! The excuse that JavaScript's success is a result of its browser monopoly is gone!

Enough is enough! The fact is; you probably love JavaScript but you're just too weak to admit it! I think the problem is that non-JS developers have got a big mouth and small hands...

My 2 cents: I am not an experienced React dev, but the React compiler came out recently with React 19, which is supposed to do the same thing as Svelte's - eliminate unnecessary DOM modifications by explicitly tracking which components rely on what state - thus making useMemo() unnecessary.

Since the article still references useMemo(), I wonder how up-to-date the rest of the article is.

As an aside, I like their use of blockquotes+details/summary blocks for inserting "afterthoughts/addendums".

It's a nice touch, and it works pretty well. Partly because, as a design choice, it forces you to add the afterthought between paragraphs, so the interruption in reading flow is minimal.

Why would performance be a goal?

If a native desktop app crashes, your users will gnash their teeth and curse your name. A web app? They shrug and refresh the page. They have been trained to do this for decades now, why would anyone believe this isn't intended behavior?

No one has a reasonable expectation of quality when it comes to the web.

This seems to be more about React than Javascript (or indirectly about the DOM). React sitting on top a browser-style DOM would be slow in any language, while Javascript itself can be surprisingly fast, especially when sticking to the right subset. It "only" needs a big and complex JS engine to get to that kind of performance.
Our webapp is nearly instant, and it's built on raw React with some sprinkling of Tanstack (their Local Collection DB is a masterpiece).

And our stack is intentionally client-heavy. We proactively synchronize all the relevant data and keep it in IndexedDB, with cross-tab coordination. The server is used only for mutating operations and for some actions that necessarily require server-side logic.

The issue with dependencies and the package size if valid, but it's also really not a big deal for performance unless you go WAAAY overboard. Or use crappy dependencies (Clerk, I'm looking at you, 2.5Mb for an auth library!?!?).

As for hydration, I found that it often slows down things. It's a valid approach when you're doing query-based apps, but when you have all the data locally, it just makes little sense. It also adds a ton of complexity, because now your code has to automagically run in multiple environments. I don't think it can really ever work reliably and safely.

To me, the main problem is that inevitably, any SPA with dozens of contributors will grow into a multi-megabyte-bundle mess.

Preventing it it's extremely hard, because the typical way of developing code is to write a ton of code, add a ton of dependencies, and let the bundler figure it out.

Visualizing the entire codebase in terms of "what imports what" is impossible with tens of thousands of files.

Even when you do splitting via async `import()`, all you need is one PR that imports something in a bad way and it bloats the bundle by hundreds of kilobytes or megabytes, because something that was magically outsourced to an async bundle via the bundler suddenly becomes mandatory in the main bundle via a static import crossing the boundary.

The OP mentions it here:

> It’s often much easier to add things on a top-level component’s context and reuse them throughout the app, than it is to add them only where needed. But doing this means you’re paying the cost before (and whether) you need it.

> It’s much simpler to add something as a synchronous top-level import and force it to be present on every code path, than it is to load it conditionally and deal with the resulting asynchronicity.

> Setting up a bundler to produce one monolithic bundle is trivial, whereas splitting things up per route with shared bundles for the common bits often involves understanding and writing some complex configuration.

You can prevent that by having strong mandatory budgets on every PR, which checks that the bundle size did not grow by more than X kB.

But even then, the accumulation of 100s/1000s of PRs each adding 1KB, bloats the bundle enough to become noticeable eventually.

Perf work is thankless work, and having one perf team trying to keep things at bay while there are dozens of teams shipping features at a fast pace is not gonna cut it.

Wasn't WebAssembly going to change all this?

Somehow that does not really have been achieved.

I think digressions about React dilute the message. Ok, we get it, react bad; but what is the actionable message here? What are the robust alternatives? There is a section on how changes to react (the introduction of hooks and of the concurrent mode) necessitated significant code changes almost amounting to rewrites; but which alternatives, other than vanilla web platform, can promise long-term stability? Which alternatives are better suited for which kinds of applications (roughly, an e-commerce site vs excalidraw)?
Wonderful article. I do maintenance programming, and many of the problems you mention with typical react apps are also code maintenance nightmares. Managing a large number of fast moving third party dependencies will destroy your developer budget, but devs cant see it because they're "Best Practices"