Hacker News new | ask | show | jobs
by francasso 671 days ago
From my experience creating complex web UIs, the performance angle of using a vdom is pure fantasy if your application is complex enough.

In fact I now strongly believe it's counter productive, because most people come to it thinking "I can just trigger however many re-renders of this large piece of UI as I like, the vdom makes it ok" and it doesn't, the performance sucks, but now you have architected the app in a way that requires a rewrite to make the app perform well.

I have seen this exact sequence of events four times, by four different teams. The second, third and fourth, as a principal architect consulting for the team I tried to intervene and advocate for a vanilla architecture that is mindful about performance, citing the issues they would likely experience with react, but to no avail. There was a lot of "oh but there many ways to avoid those issues" followed by a list of things I was presumably ignorant about.

I guess most of us need to learn things the hard way.

8 comments

There were two groups I was hoping vanillajsx would resonate with. The first is people who still buy into the React dream but are beginning to be disillusioned with its inability to deliver on its promises, and the second is people who already are fully disillusioned.

Specifically, I'm hoping to show that vanilla architectures can be not only performant, but easy to maintain with well designed code that uses stable and known patterns. Using JSX just so happens to clean up the code nicely and make the relationship between React and vanilla very visible, but that's really all it did here.

Although to be fair, the hack required to get JSX-as-DOM to work is really unfortunately and I'm not very happy with it, and I would prefer JSX to just render as an object tree that anyone can render however they want. But when I tried that for a few months or a year, it was not nearly as performant as rendering them as strings as soon as they're evaluated, which can then be cached via standard module caching. At least, that's how I got immaculatalibrary to entirely render all HTML files in ~700ms initially and ~70ms on most file changes.

I'll try to do some experimentation next week to see if I can get more performance back out of having <foo bar={qux}>child</foo> to render as {foo:{bar:qux, children:[child]}} again though, because that would absolutely be the ideal, and would unfork JSX in the same way Typed Annotations proposes to unfork JavaScript types.

Thank you for posting this! VanillaJSX is refreshingly different, and we desperately need new ideas in the front-end space to reduce the complexity and get closer to the browser. I also feel like the discussion in this thread is very rich and gives people on both sides of the fence a lot of stuff to think about.

There were two groups I was hoping vanillajsx would resonate with. The first is people who still buy into the React dream but are beginning to be disillusioned with its inability to deliver on its promises, and the second is people who already are fully disillusioned.

I don't know if you've seen it, but Alex Russell just did a blog series where he directly talks about this disillusion and proposes a move away from React for most web apps: https://infrequently.org/series/reckoning/

I am not as anti-React as that myself, but I do agree it is hard to scale up and have it perform well, not at all like the promise. As always, there are no silver bullets and you have to pick a stack that you can understand.

By the way, I made my own pitch for fully vanilla web development here: https://plainvanillaweb.com/

IMO that blog series misses the point. Knowledgeable motivated developers can make great experiences with any technology, and conversely there are bad experiences built with every technology. That series blames the people involved for not being better, but that’s just blaming plane crashes on human error and calling it a day.

- If the UK GSD is anything like USDS, using them for comparison is like comparing a pro sports team to your local high school’s. They are an outlier specifically created to be better than the average, so tautologically their stuff will be better. Code For America is a similarly odd comparison.

- The US has a massive gap in pay and prestige between public and private sector developer jobs. It’s not that this means “worse” people work at public jobs, but in general they start less experienced and can wind up in a non-learning cycle as they don’t get mentorship/guidance from more expert folks, and if they do get good independently they leave. It’s really hard to convince people to take a pay cut to work these jobs, and many of the few willing to do so instead go to CFA, USDS, etc because they want prestige and avoid all the other inefficiencies in public jobs.

I could go on about the structural problems leading to this, but suffice it to say that blaming React and other JS frameworks is a miss. For some services it’s lucky they are online at all, and a slow web page is still orders of magnitude faster than physical mail or god forbid going to a physical office. The sites could definitely be better but this is not fundamentally a problem of technology choice.

I'm sorry, but I really don't understand the point you're making here.

Frameworks have evolved over time, as we've identified better ways of doing things and as the browsers have implemented native solutions to problems that frameworks were invented to address.

For example, we don't use dojo anymore. Or ember. Or backbone. The list of once-popular frameworks that have faded is long.

The point that I (and and increasing number of other developers) have been making for a while now is that React has hit this stage. Many of the problems it was invented to solve are mostly not currently relevant as native solutions have become more widely adopted.

This has caused React to evolve into bloatware in an effort to maintain mind share. I think that evolution has had the opposite effect. I think it has driven many developers to seek simpler solutions.

I think it's completely valid to recognize framework's strengths and (especially) weaknesses. You can call this "blame" or just a justified critique.

I agree with your point that lower-skilled developers can make a mess out of any technology, but one of the supposed benefits to adopting a framework is to provide guard rails against this. If that's not working, it makes you question the fundamental value of using a framework at all.

You might find this project[0] interesting if you haven’t given it a look.

It was attempting to do something along the same lines as you first suggest

[0]: https://github.com/jridgewell/jsx2

And from my experience building complex web UIs, those team members were right -- there are many ways to avoid the issues and using vdom is great in general. True, there are situations where it falls short, which is why you will want to fall back to other techniques for those bits of architecture. Just like your JS, Python or Ruby server will call a bunch of functions written in C or the like. That doesn't mean you should write your entire backend in C.
Yes, there are ways to avoid the issues, and they involve abandoning the immediate mode illusion that react created in the name of simplicity.
Write it in React, and if you run into performance issues, there are a bunch of well-known performance optimizations you can make which are easy to discover. It's a well-trodden path that many engineers have walked before.

Write it in your own vanilla framework, and you will effectively re-invent all the complexity of React, but in a way that no one has ever done before. It's easy at small application scales, but once your app gets large, good luck debugging the thing that exists primarily in your principal engineer's head.

The fact that react is popular and has learning resources available doesn't change the argument: “immediate mode” that some boast as a React feature is an illusion that will end up hitting you, and you'll end up using it like any other retained state framework.

React is cool because it's widely used (hence more tooling and learning material) and because JSX is very convenient (it composes very well), not because the vdom works well to create an immediate mode API.

That's not the whole argument though - the argument is, what is the better alternative?
Svelte?
The "performance angle" isn't really an angle. It gets bandied around by junior devs new to React, but it's not the primary selling point of React - in fact, it's not a selling point at all. Don't believe me? Just go to http://react.dev and look - no where on the site does it say that React is a hyper-performant library. It's not! If you need blazing performance, you're best off using something much more minimal, or even vanilla JS.

When people say that React is fast, what they mean is that React can dom-diff faster than a naive O(n) approach. It means that updating a component with a thousand nested divs won't crash out your browser, like it might if you were to write the code by hand. It doesn't mean it's an objectively high-performing framework.

What React is good at is forcing you to write code in a clear, comprehensible way. Having every engineer on your team obey F(props) = state is a strict improvement over virtually any other paradigm. (Yes, you can still make a tangle of components if you try hard enough, but the complexity of the tangle is capped significantly lower than the complexity of a tangle of JS without any framework attached.)

> but it's not the primary selling point of React - in fact, it's not a selling point at all. Don't believe me? Just go to http://react.dev and look - no where on the site does it say that React is a hyper-performant library

Because now everybody know that it's not the case. But if you check the first video announcement from Facebook a decade ago or so, performance was definitely at the front, above everything else.

At the time, React was much faster than the competition (Angular 1).
Yes and the solution is to put on your big boy pants and to actually do your front-end application architecture properly.

Separate source of truth from derived data. Separate possibly valid user intent from validated state. Use contexts to organize the data dependency graph of your application. Ensure all your widgets use a consistent value type in and out, don't let events contaminate it. Use something like cursors or optics to simplify mutations and derive setters automatically.

I've never had an easier time building very complex UI functionality than with React. But it requires you to actively start reasoning about change in your code (what doesn't change), and this is something most people are not used to.

Personally I think React compiler is folly for this reason: they are taking the most interesting part of React, the part that lets you write apps that are incremental from top to bottom, and telling you it's too complicated for you to think about. Nonsense.

The issue is just that React makes pros feel like idiots unless they eat some humble pie and grok the principles and the reasons behind it. Which is that React is what you get when you try to come up with a UI architecture that can make entire classes of problems go away.

Without a VDOM, one way data flow, and diffing, your UI won't just be slow, it'll be full of secret O(n^2) cascades, random ifs to stop infinite cycles, random "let's update this state early so other code can immediately use it" ordering issues, and so on.

> I've never had an easier time building very complex UI functionality than with React.

How many frameworks did you have experience with?

> Without a VDOM, one way data flow, and diffing

you wanted to write "or" not "and", didn't you?

> Without a VDOM, one way data flow, and diffing, your UI won't just be slow, it'll be full of secret O(n^2) cascades, random ifs to stop infinite cycles, random "let's update this state early so other code can immediately use it" ordering issues, and so on.

you can adhere to the same principles (one way data flow) without vdom. Not saying it's easy at large scale but it's possible. I don't appreciate people invoking fud towards anyone opting out of their tech choice.

More than once I got asked on interviews why react is faster than vanilla JS and I had to tell them no, it isn't.
The clue would be in the fact that react is running in vanilla JS.

There is a persistent ‘learned helplessness’ tendency among some developers to assume that the frameworks they are using have access to magical mystical powers above and beyond those that their own code can make use of.

Framework code might well be better optimized or more tuned than the code you would write - but if you cared to employ similar techniques you could achieve those same gains; on the other hand, since by definition it’s more flexible than single-purpose code, it might not be optimal for your usecase.

You're technically correct (the best kind of correct), but it might be worth in an answer also exploring the possibility that they mean "Why is changing DOM a lot slower than changing VDOM a lot?"
I've faced the same issue with multiple teams,in different business domains, some with rathe heavy UIs (canvas rendering, sophisticated graphs etc). From my experience, modern frontend frameworks seem to not have taken into account these kinds of problems. To my recollection, in all of those cases, we ended up managing state and rerenders with vanilla, rather than react or angular.

A rewrite on those occasions, I do not consider possible. Most businesses are way to deep into frameworks.

What I personally advocate is to choose frameworks with valid escape hatches, and then make sure to staff a team with JavaScript programmers rather than some-framework Andies.

In an even larger scale, I advocate for web-component based solutions. I try to stay close to vanilla as much as I can. Whether I like it or not, it's the highest value professional decision, imo.

Wasn't the issue mostly solved with signals?

As far as I understand, signals make it much easier to keep the DOM updates to a minimum.

It sounds to me like GP got told stuff exactly like this, with the team eventually not actually doing the thing.
you shouldn't project from react to vdom in general:

https://dioxuslabs.com/blog/templates-diffing