svelte is far far superior to this. Instead of the verbose JSX or whatever that weird syntax is called, you literally write plain HTML in svelte and feels absolutely natural to do so
Funny. To me JSX is a much superior language compared to HTML templating. And I would say it's provably so. You can do JSX-in-JS-in-JSX recursively in a way that is "natural" and "safe" and "maintainable". And with TypeScript you get great IDE support, ability to refactor and whatnot.
No need to trust my word, just look at the huge amount of code in JSX that the world is maintaining at the moment.
I would say the only problem is the performance cost that we have to pay for this - the shadow DOM and (as a result) the hooks mess that we have in React. But it feels more like a problem that needs to be solved in order to use the much superior way of writing code (JSX). Not the other way around (sacrifice JSX for performance)
And I get that it can be overwhelming if you still haven't made the "jump", it just doesn't sound fair to criticize something that you don't understand.
Sure, it gives you expressiveness, flexibility, and templating for "free", but this comes at the expense of the separation of concerns principle, which is a bad tradeoff.
HTML is concerned with the content and structure of the page. JS is concerned with behaviour and interactivity. Using JS, or any programming language for that matter, to control how HTML is rendered introduces reasoning problems about the content and structure that just wouldn't exist if you wrote plain HTML. Yes, modern web pages are almost always dynamic, but the correct way of implementing this is via the data model, or an intermediate controller layer.
That is, JSX enables the programmer to violate the MVC/MVVM model, which is a far superior approach of building applications.
I can't count the number of times where I've stared at a JSX file and had no idea what the "component" was actually doing. Reviewing any changes to it is practically impossible because you need to keep all the layers in mind, and essentially interpret the logic and rendering in your head.
This just doesn't happen with the MVC/MVVM approach. Every layer has a specific concern, and you can clearly trace the data flow, from when the data is read, to how it's used and manipulated, to how it's finally rendered. This is a major win for building maintainable applications, and disregarding this has made frontend web development an absolute hell.
It gets even worse when CSS can be written in JS as well... This "everything in JS" trend is an abomination.
Svelte does the right thing here and at least conceptually separates the layers, but at the end of the day, you're still writing in a DSL that gets compiled into JS, which has its own quirks and issues.
The frontend industry needs a hard reset that takes us away from this gigantic pile of abstractions and back to using native web technologies, which are quite capable on their own by now. Recently I've found Nue and Datastar to be the much needed steps in the right direction.
> practically impossible because you need to keep all the layers in mind…
> …with the MVC/MVVM approach. Every layer has a specific concern…
Do we need to keep all the layers in mind, or not?
Separation-of-concerns is not a virtue. It’s a trade off between separation-of-concerns and locality-of-behavior. SoC can be a benefit, if it matches your team structure. But also, any abstraction has a cost of increased cognitive load (and even worse is premature, wrong abstractions).
If I have to look at 5 files instead of 1, the 5 files better pay for itself in some way (and in a small team, there’s almost no room for that to happen).
I can’t prove this obviously, but if I were betting, I’d expect more businesses have failed due to lack of velocity from over-engineered SoC apps, while the LoB monolith that’s easy for a small team to reason about found the right abstractions and won the market share (and later got rewritten as a SoC app, e.g. Instagram).
> Do we need to keep all the layers in mind, or not?
With MVC/MVVM? Yes, but not all at once. That is, you focus on one layer at a time. You think about its inputs and outputs, and how it interacts with other layers. Then you follow the data to the next layer, and so on.
With JSX, or any project that disregards SoC, you're forced to think about all layers at once. You have to think about how the JS processes the data, and at the same time how this impacts the content and final rendering.
It would be like if on the backend you would mix business logic and data processing layers, or more accurately, put business logic AND your views inside your database. There are developers who don't mind or even argue for this approach, but most developers would agree that this is an insane way to build applications. Yet on the frontend, for some reason, everyone is fine with this.
To give a concrete example, take a look at this page from the React docs[1]. Ask yourself this: what is the structure of the page at any point in time? Is any component modifying data? What happens if it does? What happens if a component renders a structure that is incompatible with other components?
This is a trivial example, so some of the answers are evident, but in a real-world application these and many other questions are very difficult to answer. Especially by staring at the code during a review. I've found that the only reliable way to review code in a modern frontend framework is to run it locally, see what the behavior and rendering is, and correlate that with the changes. And, of course, since there is usually a complete disregard for UI and E2E testing of any kind, this process is error-prone and regressions are common.
> It’s a trade off between separation-of-concerns and locality-of-behavior.
These are often seen as opposing principles, but it's possible to have both. A single HTML file can contain HTML, JS and CSS. Each section has a single concern, but would you argue that LoB isn't preserved?
> any abstraction has a cost of increased cognitive load
None of these principles or models are abstractions. They're design patterns that suggest a certain way of thinking about and organizing an application that makes reasoning about it and maintenance easier.
> If I have to look at 5 files instead of 1, the 5 files better pay for itself in some way
Again, SoC is not about putting things in different files. It's about a logical separation between different parts of the codebase. Whether that happens in a single file or multiple is up to the team to decide.
Well, I guess personal preference is also a thing. But I would say that the "market" doesn't agree with your thoughts on the matter (and I don't also, but my opinion matters way less).
You can write MVVM as an unmaintainable mess also. From my experience as a freelancer, I have had much harder time fixing badly written Angular projects (all versions) than such written in React. It seems that people as a whole tend to produce much better React than any other UI code that I have encountered ever. (and I have done my share of Desktop/Mobile too). Flutter is great, but it's also practically React in a proper language.
> I have had much harder time fixing badly written Angular projects (all versions) than such written in React.
What is the inherent issue with Angular? Data fetching is done by services, components use them, components' presentation logic is in html/scss files. If a component is particularly simple/low level, it takes data as input which can passed by the higher level component with help of services. I have found this to be very easy to reason about as long as the structure keeps in mind what each bit's role is in the big picture. Separation while keeping logically connected things close e.g. the component and its html/scss are usually kept together.
> I would say that the "market" doesn't agree with your thoughts on the matter
I'm well aware. :) But it wouldn't be the first time that large-scale groupthink has led an industry or society in the wrong direction.
The problem is that there is now an entire generation or two of frontend developers who are "senior" based on years of experience who have only known web development post-React. They're not really aware of working with anything other than a framework, what these frameworks and libraries initially set out to solve, whether those same problems still exist today, or what is possible with modern native web technologies. They in turn go on to invent new frameworks and libraries to address some of the shortcomings of what they're used to working with, but without considering the possibility that these massive frameworks might not be needed at all. This is why we need developers with experience in the early days of the web, those with different backgrounds, and those who are willing to rethink the modern approach from first principles, to guide the industry towards saner development environments, and more maintainable and performant projects.
Datastar, for example, takes a radically different approach, and while I can't say whether it's the right one for every project, the results speak for themselves. It powers projects that would be a nightmare to build, if not outright impossible, with any other framework, with incredible performance, all with a tiny fraction of code and complexity. It's not that Datastar is somehow magical—the author simply took a step back and used technologies that already exist, which no one else thought to put together in the same way.
> You can write MVVM as an unmaintainable mess also.
I don't disagree, but it's much harder to do than with most mainstream frontend frameworks. JSX by definition mixes different concerns, and leaves the door open to not care about this separation at all. The only unit of organization in a modern frontend framework is a "component"; a concept so nebulous to be practically useless. When everything is a component, nothing is, and you might as well not use it at all[1]. The only reason we do, is because we want to avoid code duplication. That on its own doesn't encourage designing applications with a sane structure in mind, and doesn't emphasize the idea that using different layers with separate concerns helps with reasoning and long-term maintainability. These are not novel ideas, mind you. They've existed for decades, yet after React we collectively decided to throw them out the window.
IMO frontend web development peaked around 2010 with Knockout.js. It provided just the right amount of abstraction to allow us to build highly interactive web apps without the maintenance problems of jQuery, and without the insanity of JSX, virtual DOM, diffing, reconciliation, SSR, bloat and supply chain vulnerability issues of incomprehensibly large dependency trees, etc.
[1]: You can see this confusion here[2]. They suggest separating components into "container" (or "controller") and "presentation" components, but then confusingly also say: "[container components] may contain both presentational and container components* inside", and that double asterisk is never addressed... Huh?
In practice, in all the React and Vue projects I've worked on (which admittedly isn't many; I don't consider myself a frontend developer), I've never seen this separation being followed, and components end up being a dumping ground for loosely-related content, behavior and style of things that exist on the screen.
Turns out that even the 2015 Dan Abramov article they link to[3] has an update from 2019 where he backtracks the separation suggestion. Wat. "Hooks" are supposed to be the modern solution... Yeah, sure, I'll trust you _now_, Dan.
But wait, actually, "signals" are the modern _modern_ solution![4] JFC, this is like a carousel from hell...
Well, you can be a purist, or you can be practical. I write code, users run it, I get paid... While you are fixing the "modern web technologies". And I give you this, things are getting much better and I hope one day we'll run JSX natively in the browser without a build step ;)
I totally agree about Svelte and the benefits of layer separation. I would say that philosophically, Svelte not only separates the layers, but gives HTML a special place among them, calling it "The Mother Language". [0]
I agree that JSX is a mistake, but I disagree with the "separation of concerns" part. The "separation" is useful when we know that separate people are going to be editing and changing the presentation versus the UI code. A bit like the .obc vs .h vs .nib files of older MacOS versions - you can carefully edit the .nib, and with any luck you don't want to touch the "actual" code.
But for most modern SPA UIs, this is actually less useful - because what you output into the DOM and the behavior are so intertwined. With setups like HTMX, for example, easily half of your HTML attributes can be interactivity-related. Yes, someone may be editing those separately - but they hardly will be able to edit them without any care for preserving the attributes, preserving the correct nesting the template needs to support the UI code, and on and on.
Hosting a "component" together with everything it needs to render inside one file is actually very handy, 90% of the time.
Where JSX is an issue is in the language department. The single reason we were forced onto the Webpack bandwagon - with all the years of endless tweaking, debugging and suffering that followed - was JSX, as you would have to jump through hoops to use React without the foreign syntax. A default React component was not valid JS, point.
So - expressing the DOM imperatively inside the component is fine. Shoehorning a syntax (which also requires workarounds like `className`) into another syntax and then requiring a preprocessor just for your code to work is... meh.
Yes, it feels super natural, which is actually a good way to describe Svelte's overall DX. Part of the reason it feels so natural in relation to HTML is that Svelte treats it as "The Mother Language". [0]