There is definitely no built-in support for those things, but I don't think it's fair to call them second class citizens in the React world. AngularJS bundled an entire http client back in the day, but that doesn't make it more "first class" in the AngularJS ecosystem than in Vue or React!
My experience with Vue has been pretty mixed here, though. It's nice having everything in one file, sure, but it's also a pain having to create a new file whenever you want a new component. In JSX-based frameworks, I tend to start with a component in a file, then split it up into multiple components in one file, then finally into different components in different files as I'm going along - the same as I would do for normal Javascript functions. That's difficult to do in Vue, and I often find components tend to grow much larger and more unwieldy because it's easier to just add more to a single component than to split it into multiple components.
I also like the way CSS is built in, but I'm unconvinced that magic style scoping is all that helpful. I found myself fighting against it, and trying to remember the correct `::v-deep` incantation more often than I'd like. For me, the ideal abstraction here is CSS modules, where the class names are scoped, but the actual declarations behave like normal CSS. I never managed to get CSS modules to work with Vue, but we were stuck on Vue 2 for a long time, and that might have changed with more recent versions.
But I think that's the thing: there isn't really a clear "best in class" here. Different tools work for different people and in different contexts. You talk about the awfulness of CSS-in-JS, but last time I used it, I found it gave a really good balance between conventional CSS (albeit not in CSS format), while still being collocated with JS components. There are definitely downsides, but there are downsides in most of these solutions.
> For me, the ideal abstraction here is CSS modules, where the class names are scoped, but the actual declarations behave like normal CSS.
How is this different from Vue or Svelte scoped style blocks? Those are just normal CSS with scoped class names.
> Different tools work for different people and in different contexts. You talk about the awfulness of CSS-in-JS, but last time I used it, I found it gave a really good balance between conventional CSS (albeit not in CSS format), while still being collocated with JS components.
People think too much about how these things work for themselves and their own skillsets, not whether it prevents other great people from contributing as easily. I know HTML/CSS developers who are way better than the average React dev at building great clean and accessible UIs, but they aren't as strong in JS and end up struggling with unnecessarily complicated JS solutions to things that don't need them.
Besides the colocation what other benefits did CSS-in-JS provide you besides the familiarity of JS logic? This feels like again a solution to solve a limitation of React, not actually the best solution.
CSS modules work quite differently from scoped CSS. In scoped CSS, every element in a component is given an extra data attribute unique to that component. Then when you write your CSS, each declaration is given an implicit extra selector that scopes it so that it only affects elements in that component. As an example, the selector `.header > nav:hover` would be implicitly transformed into `.header > nav[data-535728]:hover`, and every element in that component would be generated with the `data-535728` attribute.
In contrast, CSS modules is far simpler: every class used in a CSS file is replaced with a random identifier (normally something deterministic), and any JS file that imports that CSS file will receive an object mapping the original class names to the new identifiers. Essentially, the only change from normal CSS is that class names are no longer global - everything else remains the same.
In my experience, I tend to run into far fewer surprising situations with CSS modules because it really is just CSS. If I target a class and all of its children, then I get what I expect, regardless of how the components are laid out in practice. In contrast, with scoped CSS, I tend to find that the scoping rules get in the way - my CSS is now tied to my components, as opposed to being able to be used and reused in multiple places. It's not a big issue (and I've used it plenty, and most of the time it's fine), but I always feel like it's an extra layer on top of CSS that I don't actually need.
Whereas, ironically, CSS-in-JS tends to feel closer to true CSS (and CSS modules) because there aren't any surprises. It's just CSS declarations (albeit often written in an unusual syntax), except that class names are locally scoped. In that sense, I can use my existing CSS knowledge and craft selectors however I want.
I understand the value of SFCs for people who don't feel as comfortable with the scripting side of things, but I do wonder if that's a bit of a false economy. At the end of the day, Vue is a tool for writing Javascript components. If you've got a team that doesn't want to write Javascript, then something like Alpine.js is probably a much better option - minimise the JS side of things completely and just concentrate on the HTML and CSS sides. But component-based web development is going to involve combining Javascript, CSS, and the DOM, and that involves understanding all three technologies, and not just specialising in one of them.
E: as a complete aside, I love the user name! I've just finished rereading the Watch books and I'm deciding which thread to go down next.
The difference between Vue/Svelte style scoped CSS and CSS modules isn't really that different in practice. When working with a larger team it is harder to enforce being careful with class name uniqueness, so the auto-scoping is beneficial but in a personal project I honestly don't mind turning off scoping entirely and just being strict about BEM class names. I LIKE the cascade part of CSS. So when working with a team Vue/Svelte-style scoping gives me the best of both worlds, global classes when I need them, scoped classes when I want to keep it component-specific.
The issue isn't that the companies/people I work with don't want to write JS, it's that they ONLY want to write JS. They don't hire the people that know HTML/CSS and accessibility better than their React devs so they don't even know what they are missing, they just think it is normal for implementation to be clunky, not match designs, and have poor performance. This is pretty much the standard at most early stage SAAS startups except the ones started by people who actually care about this stuff and understand it technically. At every company I have worked with (usually under 100 people) I as product designer have written more CSS than any front-end developer.
The point is to make codebases that are accessible to people who come from all sorts of backgrounds, not just JS developers. I have worked with designers who knew HTML/CSS well and they were so happy to be able to write simple template logic and plain old class names in Vue without having to figure out the correct JS syntax for modifying an array of style objects or writing a conditional and not leaving an accidental 0. Passing classes and props into child components and not having to explicitly tell it what to do with each one makes building JS components a LOT easier for people who aren't JS experts.
Discworld is a true joy, I miss Terry Pratchett! I read the books in publishing order, but I have had the urge to go back and read them as sets of related themes.
My experience with Vue has been pretty mixed here, though. It's nice having everything in one file, sure, but it's also a pain having to create a new file whenever you want a new component. In JSX-based frameworks, I tend to start with a component in a file, then split it up into multiple components in one file, then finally into different components in different files as I'm going along - the same as I would do for normal Javascript functions. That's difficult to do in Vue, and I often find components tend to grow much larger and more unwieldy because it's easier to just add more to a single component than to split it into multiple components.
I also like the way CSS is built in, but I'm unconvinced that magic style scoping is all that helpful. I found myself fighting against it, and trying to remember the correct `::v-deep` incantation more often than I'd like. For me, the ideal abstraction here is CSS modules, where the class names are scoped, but the actual declarations behave like normal CSS. I never managed to get CSS modules to work with Vue, but we were stuck on Vue 2 for a long time, and that might have changed with more recent versions.
But I think that's the thing: there isn't really a clear "best in class" here. Different tools work for different people and in different contexts. You talk about the awfulness of CSS-in-JS, but last time I used it, I found it gave a really good balance between conventional CSS (albeit not in CSS format), while still being collocated with JS components. There are definitely downsides, but there are downsides in most of these solutions.