JS frameworks decision paralysis
I’m a bit late with a reaction, but I quited frontend development right when the madness hit the peak and it’s worth taking a glance back. It’s sad to conclude that madness won: we officially have approx 50-100 different JS-related frameworks or their combinations for building websites:
https://github.com/krausest/js-framework-benchmark
https://github.com/gothinkster/realworld
Obvious question: why so many frameworks if we have React.js? Remix? Next.js?
But let’s start from afar. First and foremost thing we should consider: writing programs in plain JavaScript sucks ass. Handling browser’s DOM with decades of legacy sucks even more. You got to employ a small subset of features and abilities to avoid drowning in the see of endless weird combinations of them and a hell of mutable maps that constitute a foundation of JavaScript. You write a code, some other programmer writes his code that takes your object, changes its structure, and returns it back — especially if the object is semi-global one. Prototype chain pollution can actually become a nightmare to deal with.
Once again the core principle of dealing with such a dangerous technology is: use a carefully curated subset of it. Preferably automate the checks — which is kinda why Douglas Crockford made a linter 20+ years ago.
But it appreas that linters are not enough, they cannot check correctness across many functions. Okay, we’ve got TypeScript. It can introduce typechecks into your project, but it cannot forbid you from changing external object via valid operations and breaking an unrelated code i.e. violation of modularity i.e. it catches low-level mistakes but not medium/higher logic breakage.
At aproximately same time (as TS) somewhere deep inside Facebook a React.js was conceived. It was supposed to solve exactly this problem: I don’t break your code, you don’t break mine. Because all the data structures are isolated, the data flows one way. Second problem React.js solved is browsers inconsistency (hence VDOM and synthetic events) thus basically creating a “browser in browser”.
That’s the point where industry got stuck — half of the induestry employs React.js + TS nowadays. What about Vue, Svelte, Solid? Nah, too immature.
Unfortunately, React.js by 2018 actually managed to resolve the third big mistake — classes in JS, by introducing hooks. Last source of tangled state is gone. So, React.js is good?
Ironically, by the same time we’ve got ES6 and Internet Explorer finally died by 2020-2021. So now we have a consistent DOM, native events, Proxy for reactivity, shadow root and CSS variables. So we can drop this “browser in browser” thing, right? Or not?
Mass engineering seems like a drunkard — you cannot give him freedom of choice, you cannot help him with money, because he will get drunk, get into a brawl, or drive a car and crash. React.js used to solve a real problem, but nowadays it solves the only one problem: how to put a straightjacket onto a dev to limit the damage from a low-competence/low-motivation engineer writing spaghetti code. So we can employ a dude from React.js bootcamp who learned React.js before he could do a plain HTML.
However, by 2025 I fail to acomprehend the situation, because after 2023 we have a flood of highly skilled coders on the market. But the industry still optimizes for a sloppy worker.
The amount of new frameworks clearly says we can do better, and people see it can be done much better. React.js creates overbloated websites that are slow to load, that are blank pages during the load. Yes, we now have Preact and Mithril which are basically a historical experiment of “what if React.js was created when browsers followed web standards?”. However react-like frameworks themselves do not solve the state handling.
Okay, we have Redux — but to employ Redux you need lots of boilerplate (who said “Copilot”?). You can solve the “empty SEO page” by employing SSR (Remix/Next.js) — and now you have the React.js+Redux+Remix combo that is not nearly simple, not fast to iterate, and you have state desync/hydration problems, and your website is still so heavy it takes a while to load it via 4G connection. That’s a price of solving the problems that don’t exist anymore, but not solving the ones in a plain sight. React.js slowly turns into Cobol — “well, we just use it because we used to use it… and we have lots of services in Cobol”.
I know there are Zustand, React Query, SWR, these are different tradeoffs, but overall the problem is the same.
I also know there are lots of ready-made libs for React.js, however, there are even more framework-agnostic libs — so the developer not restricted by a framework wins in the end.
Occasionally it becomes hillarious:
https://github.com/solidjs/solid/discussions/1042
Solid makes re-rendering components really hard and inconsistent
When I finally make it re-render it is really inefficient
People try to use SolidJS like it is React.js, while you should not do it, you don’t hammer a nail with a screwriver (however, wtih JS classes, Angular, and Effect you can almost say screwdriving a nail is a “best practice”). Doing half the VDOM tree traversal to update a single element class is wrong and you should not do it. We can do a reactivity without prop drilling and without Redux boilerplate. We can avoid mass fetches without React Query having its own cache inconsistency problems. In the end we can make static page a static HTML and introduce limited amount of reactivity via HTMX — not every website is a Facebook, you know.
Ironically, the original article on Functional Reactive Programming (fundamental idea behind React.js) was called Functional Reactive Animation. But React.js is not handling DOM animation, it’s mostly displaying static frames. You wanna dynamic app with thousands of entities? Just forget it, any VDOM-based framework (React, Preact, Vue, Mithril) would implode on such a task. Animations? You got to access DOM directly via useRef and requestAnimationFrame. Canvas/WebGL? Nah, just forget it, it’s not react-friendly. You cannot be too sarcastic when a “reactive” framework actually limits your reactivity just so you can hire a bootcamp graduate.
There are near-luddites like Heydon Pickering or Chris Ferdinandi, and I can understand their thirst for clear simple solutions of simple problems i.e. drop all JS frameworks and use vanilla JS only when strictly needed. However, when you drop all the solutions, suddenly it appears that some of them were solving real problems. I mean if you look at https://github.com/cferdinandi/reef — no solutions for component props-events two-way changes propogation (you’ll have to use web components or do it yourself), no handling of complex conditionals or arrays of children, and in the end your complex reef-based app you will leak the watchers (i.e. RAM) because there are no weak refs and no explicit unreferencing, you have a big ball of mutual strong references.
Wanna suggestion as a summary? If you want to do a simple-to-medium complexity web app with all-JS fullstack — just employ Astro+SolidJS. It’s not the best solution, but at least well established and supported. I still really think you should not employ JS on a server side, but you cannot just tell people to obey speed limits and use seat belts. You can use node.js, you can employ react.js and next.js, but there are no technical reasons to do so.