Hacker News new | ask | show | jobs
by CharlieDigital 577 days ago

    >  ...might end up rediscovering up close why people moved to Vue/React/Angular in droves instead of jQuery
Vue, React, and Angular are fundamentally MVC in disguise: a "controller" modifies some state (model) and on the next render cycle, the "view" is updated by the library/framework to draw the change. (Simplifying here to ignore details of the implementation like vDOM, components, etc.)

Not so with jQuery. You draw the change directly. You can write a framework on top of jQuery to achieve something similar where a model/state gets updated -> detect the change -> jQuery to draw the change. (That might be interesting or perhaps something like this already exists.)

In other words, in Vue, React, and Angular, you are discouraged from doing direct DOM manipulation; you always modify some state from which the framework applies the DOM changes and in jQuery, it's the opposite: you directly manipulate the DOM in reaction to some action. So the reason why people moved is that an MVC-aligned paradigm is ultimately more productive and a better abstraction than directly manipulating trees of rectangles.

3 comments

indeed, good description. Noting that vue etc. are MVC in the browser, with (typically) calls to json http endpoints on the back end to read/write data.

JQuery was born in a time of server-side rendering (SSR) where, in essence, MVC happened in the back end and it shipped html to the browser. In that model, the browser is essentially a terminal that renders output formed in the back end. JQuery was one of the early libraries to promote behaviour in the browser instead of "browser as terminal".

It feels like there's bit of a swing back to the SSR model, e.g. with the growing popularity of htmx [0] though there are still many strong proponents of the MVC-in-browser approach.

[0] https://htmx.org/

    > JQuery was born in a time of server-side rendering (SSR) where, in essence, MVC happened in the back end and it shipped html to the browser.
Yeah, I think this is nail on the head. It was also a time of smaller apps and smaller teams so it was easier to manage the state even with direct mutation on the DOM tree.

With bigger and more complex apps, you needed multiple teams and now it's not possible to really effectively track the state of the DOM if multiple teams could be manipulating it from different components.

You can see that shadow DOM and web components is one way of thinking about this problem. Separating the render from the state (a la Vue, React, Angular et al) is another.

Very true. But it doesn't matter if you're building a typical website instead of an SPA, and the only "state" you care about are little things like whether a checkbox is checked.

Even in that case, many of the fancy effects people used jQuery for can now be implemented in pure CSS. These days, when I'm working on a simple blog or landing page, I find that I don't even use much JS at all. It's HTML and CSS, not full-blown SPA frameworks, that have gradually replaced jQuery for me.

Yes, agree.

I do think that using either web components or Lit offers a nice layer of encapsulation and reuse as well as some convenience.

There are a lot of options nowadays.

Why is it more productive? I like your description, but this statement needs elaboration.

When I look at modern frameworks, all I see is unconstructive complexity that sucks productivity

The answer is "state".

Imagine a big project with multiple teams.

Now they are building different components that all need to modify the state of the UI. With jQuery, it would be easy to create a UI state that your team doesn't understand and it's hard to trace exactly which mutation caused it. You're depending on a `div > div > span.firstName` and suddenly, someone injected a `div > div > div+span.firstName`.

When there's a model, it's easier to trace the model because our tooling (language servers in editors) can trace and track references. We can verify the behavior using tests by mutating the state of the model and then checking if we get the correct output state. This is also doable with direct DOM manipulation, but it's not as easy.

So ultimately, the "MVC-like" nature of Vue, React, Angular are productive for the same reason why MVC itself is productive compared to directly drawing rectangles.

I would say that it is structured complexity. Modifying a reactive variable is more complex than editing the DOM directly, true, but it minimizes the number of sources of truth. The developer no longer has to worry about keeping the on-page elements and JS variables in sync; that happens automatically.

Managing just your application's state, while letting some template logic know where to embed that info into the app, scales far better.

If you measure complexity strictly by the amount of code running, then a React or Vue app will likely be more complex. If you consider just the actual application logic, it's usually far simpler. This is especially true if you utilize components, which lend themselves well to rapid development with fewer side effects.

The complexity is the infrastructure you need to build an application with a JS framework, versus just including the libraries that you needed in script tags and done. Do we really need a build system for JS? Probably to make something as complex as Google Docs that is an application that runs in the browser yes, but not for 99% of web pages that you see each days.
Complexity has to live somewhere. We use abstraction to better manage it, and keep our codebases scalable and manageable. Yes it's not as efficient as it would be if every single function call were carefully planned for and orchestrated, but that's not feasible for modern applications that do many things.

It's the same way on the desktop side. Writing everything in assembly instructions would technically be the least "complex", but it'd also be utterly insane and error-prone to do it that way. Even mid-level abstractions like C++ are hard to get right. It's why many modern apps are built in higher-level abstractions, because they're easier, more reliable, and fast enough.

It's really no different for a website. You can put all of your state in one place, bridge different libraries, and manually sync DOM changes, but you're essentially just frontloading the complexity. Abstraction is an important concept in structuring your codebase into clean and maintainable code, even if it is technically more complex.

I won't argue that React doesn't get overused for otherwise-simple pages, but many pages are not simple. The web today is full of interactions, tabs, dropdowns, search bars, notifications, modals, and tooltips. It all needs to respond to your device's form factor and input method. Every network request requires error handling. It needs to be routed, cached, and served smoothly and correctly.

It's a lot. It's a lot to manage in one layer. I am content to let some of that complexity be managed by Vue, or React, or whichever framework we're discussing. If it lets me worry just about my application's logic, and it simplifies the templating, error handling, routing, and so on, that makes things easier and less error-prone for me.

Honestly, I've written plenty of web apps in vanilla JS. I've experimented enough with closures, IIFEs, classes, and other techniques for managing state. It really doesn't matter how careful you are, any sufficiently-complex project will always turn into spaghetti. Frameworks help us stave that off, at least for a little while. Their component-based architecture makes relationships more explicit, and much easier to isolate. I particularly like Vue's Single-File Component (SFC) concept which organizes components into logic, template, and styling.

Not all frameworks require a build system though, and there's plenty of options available for tackling smaller problems. Alpine is great for reactive data. htmx helps manage apps with many server calls. You don't necessarily need the full React or Vue package, if your app isn't so complex.

But if it is, I think you'll be glad to have them.

The key problem all these frameworks solve is to let you store (and track changes to) data in a different structure than your UI. The moment you're not building a pure CRUD app, where the UI and the data always follow the exact same tree structure, but something more complex, tightly coupling the data to the UI like you'd do with jQuery apps gets messy and problematic.

To be frank, when all you see is "complexity that sucks productivity" I wonder whether you've ever tried to make a non-trivial SPA without them. You'll either end up building lots of spaghetti (like happened with every jQuery app I ever saw), or inventing your own makeshift framework that solves the same problems, kinda-sorta, hopefully-good-enough.

    > I wonder whether you've ever tried to make a non-trivial SPA without them.
I personally have. React launched in 2013. Here's a real-time enabled browser chat app I built in 2011: https://www.youtube.com/watch?v=WG_W0VxjzbM and at this point, it had been years of building similarly complex JavaScript apps.

Many sufficiently complex apps existed long before React. The "OG" Outlook Web App was certainly not lacking in complexity.

The challenge is that it requires far more skill and a deeper understanding of DOM, JavaScript, and CSS. It requires being more diligent about encapsulating logic.

What React did was it made front-end more accessible to a wider audience. The skill barrier is lower (though traded for complexity elsewhere, IMO). Devs now probably start with React and Tailwind before learning raw DOM and CSS. The good ones will eventually learn it, the mediocre ones will vaguely know that it exists.