It is very true that the types of situations you mentioned are very painful with just HTML/CSS/Vanilla JS. However, React is no longer the only game in town for the things you mentioned. LowJS frameworks like Unpoly with a good server side rendering framework can handle the things you've described and a lot more. For example, you can use Unpoly with a server-side framework to allow layers to either act independently or to cascade information down to lower layers for multi-page/modal window flows that need to share information all without full page reloads. [1] Using layers you could build some pretty decent sized apps, Unpoly gives an example [1] showing (conceptually) how you could build large parts of Gmail with layers. You can also do things like dynamic forms with a bit of code on the back end. You get all this without needing to keep state in sync between the front end and the back end.
There will be cases where Unpoly (which can do quite a lot) only does 95% (or whatever) of your requirements. In those cases you can sprinkle in a bit of Vanilla JS to help fill the gap. Additionally, there will be some cases where Unpoly isn't at all suitable, like if you're building something that is extremely interactive (i.e. the next Google Docs/Maps or similar). However, those cases keep getting smaller as these LowJS Frameworks improve. Everyone's case is a very particular set of circumstances and this might not apply at all to your situation, but others are finding success with using HTML over the wire types of approaches. [3] One final thing to note that's often overlooked is that CSS' capabilities are growing, and can do a more than in the past. All things to think about before reflexively defaulting to React.
> In those cases you can sprinkle in a bit of Vanilla JS to help fill the gap.
I think this is where your proposition causes me to raise an eyebrow.
If you can stay 100% within your framework then I can accept it will be simpler and more productive than React.
But this architecture of “95% in-framework and 5% JavaScript spaghetti”… I don’t trust that. That sounds like a lot of days burnt trying to bolt that one feature onto a framework that doesn’t support them. And a lot of days debugging into the framework internals to try to understand which possible implementation of that feature won’t blow up by crossing some assumption of the framework. And I’m not sure you can argue as convincingly that’s less effort than the 100% React solution.
IMO the beauty of React is you can do anything you’re asked to do. There’s alway a “React-y” way to do something. That’s because it’s lower level than a framework. It’s just a set of primitives. And pretty well thought out, battle tested primitives at that.
And, when you do it right, you can have a very large piece of software that’s made entirely of small, functional modules. And there are simple rules for following the control flow. Once you understand those rules (and it does take a few years to really grok them) then you can drop in to any module in a massive system and follow the control flow easily.
In a framework you don’t have that. There’s various points where your code calls into some declarative interface the framework has exposed, and then *magic happens* and the wrong behavior pops out on some other end of the application. It’s a debugging brick wall and in my experience it’s a massive time sink. Even in React many third party libraries also put you in this position, but that’s a whole other rant…
But that is React’s superpower: when you use it correctly your time spent debugging any one defect is closer to O(1). With more “black box” frameworks your debugging time can be more like O(n), where n is the size of the codebase.
For small codebases, there’s no difference, or maybe the framework is faster even. But for large codebases I think React has a massive productivity boost there.
And all of this is predicated on that 5% number you quoted. If you can stay 100% within the framework, go for it. But in my experience business needs are always going be pushing 5%, 10%, 20% of the “special requests” and if you don’t plan for that, they can start taking up 50%, 60%, 70% of your time.
There are ways to most anything. The question is whether it is a good or not. The best/worst thing React did to web development is taking a cleaver and splitting the front end and the back end down the middle. It is the best because it provided a clear answer to adding dynamic content that didn't end up a horrible mess like jQuery at scale. However, the worst thing it did was split the front end and the back end. The typical setup of, a front and developer and a backend developer, often on separate teams is a big problem spawned by React. Whenever you want to do anything new in these situations, you need to meet with the backend developers to build endpoints for you. This slows things down tremendously and creates friction during development. Even moderately interactive pages, going through all of this is way overkill and you're very likely wasting so much time (all other things being equal). With traditional server-side frameworks (e.g., Laravel, Django, Rails, etc.) you don't need to wait for anyone to build your endpoints or set up a byzantine labyrinth of JS tooling before you can code the first line. Don't get me wrong, React is a great tool and the best tool to building many SPAs, but it isn't the right tool for every job. There's a reason why so many people in this post are saying they've had it with React, which isn't something one used to see on this site. Now it's fairly commonplace to see people looking for greener pastures.
> But this architecture of “95% in-framework and 5% JavaScript spaghetti”… I don’t trust that. That sounds like a lot of days burnt trying to bolt that one feature onto a framework that doesn’t support them. And a lot of days debugging into the framework internals to try to understand which possible implementation of that feature won’t blow up by crossing some assumption of the framework. And I’m not sure you can argue as convincingly that’s less effort than the 100% React solution.
That's a pretty easy answer, you can drop in a React/VanillaJS Web Components or VueJS Components whenever you like. If you're still feeling unsure, just go with Hotwire, which has an small JS framework (Stimulus) for dealing with the odd bits of Vanilla JS to give your HTML a bit more interactivity. Now you have a belts and suspenders backstop to handle feature creep and increasing interactivity. There are other tools for doing similar things to Stimulus.
> But that is React’s superpower: when you use it correctly your time spent debugging any one defect is closer to O(1).
Nothing is for free. The tradeoff is that you're going to spend more time figuring out state sync issues/debugging/refactoring your API endpoints.
> And all of this is predicated on that 5% number you quoted. If you can stay 100% within the framework, go for it. But in my experience business needs are always going be pushing 5%, 10%, 20% of the “special requests” and if you don’t plan for that, they can start taking up 50%, 60%, 70% of your time.
In an effort gently persuade, I may have undersold just how little (i.e., 0%) Javascript you'll need to write for many types of common pages and patterns.
HTML over the wire frameworks all came out around 2015-2016, which means they're all battle tested and have seen a lot of use cases. Turbolinks/Hotwire and Unpoly both came out of companies who are presently or started out as web agencies. Basecamp has been powered by HTML over the wire for years. Now Hey.com email is showing what this approach can do for a pretty ambitious application. Part of the founder's pitch for Unpoly is that he uses Unpoly and in his agency and supports his apps for a long time, so you need not worry about it going anywhere. Because of this, the number of use cases these frameworks have seen and handle is significant. Web dev shops constantly deal with exactly the sort of feature creep you mentioned. If these frameworks were a big problem or had huge limitations that you're concerned about, their founders supporting companies would have abandoned them long ago, to say nothing about all their users. Time is money in web agencies, so I would be surprised if they experience the situation you're describing.
I'm not saying HTML over the wire is the end-all-be-all, only that they are good enough today to remove the always default to React mindset for many shops and situations.
There will be cases where Unpoly (which can do quite a lot) only does 95% (or whatever) of your requirements. In those cases you can sprinkle in a bit of Vanilla JS to help fill the gap. Additionally, there will be some cases where Unpoly isn't at all suitable, like if you're building something that is extremely interactive (i.e. the next Google Docs/Maps or similar). However, those cases keep getting smaller as these LowJS Frameworks improve. Everyone's case is a very particular set of circumstances and this might not apply at all to your situation, but others are finding success with using HTML over the wire types of approaches. [3] One final thing to note that's often overlooked is that CSS' capabilities are growing, and can do a more than in the past. All things to think about before reflexively defaulting to React.
[1] https://unpoly.com/up.layer
[2] https://unpoly.com/tutorial
[3] https://htmx.org/essays/a-real-world-react-to-htmx-port/