nl-design-system / denhaag

Work in Progress: Den Haag Design System based on the NL Design System architecture
https://nl-design-system.github.io/denhaag/
Other
12 stars 7 forks source link

Importing a single component from components-react imports the styles for all components #812

Open bddjong opened 2 years ago

bddjong commented 2 years ago

https://codesandbox.io/s/nlds-feedback-1-fwy6h9

mjcarsjens commented 2 years ago

@bddjong a penny for your thoughts about the following?

basically the issue here is our entire structure of imports. The components-react package exports all components. Now how this is built is basically all the JS is bundled together into one big file, and because we simply import the .scss files directly all these imports now are also used in the compiled index.js. This is not easily solved by adding for example preserveModules to the rollup config. If you still want to be able to directly import the components from the root package (so e.g. import { FormLabel } from '@gemeente-denhaag/components-react' instead of having to specify the location import { FormLabel } from '@gemeente-denhaag/components-react/components/FormLabel') this issue will still exist and adding preserveModules will only make a bigger mess of our compiled packages.

The issue is practically that the moment our components-react package is imported (whether something is actually used or not) all the css is injected in the HTML head. Now I see two solutions for this issue:

export const Card: React.FC = ({ archived = false, ...props }: CardProps) => {

if (!cssLoaded) { import('./card.scss'); cssLoaded = true; }

... rest of component ... }


While not exactly elegant it does work (quick sidenote: this setup will result again in one built JS file for all the components, but now also a single JS file for every `.scss` file imported this way).

- Change our setup to use (s)css modules, so every component still injects its css in the head but with pre- and post-fixed classes resulting in no actual clashes on other bits of the end-users application which might use the same classes as we do.  Big downside however is that this setup will break our `components-css` package as all the classes there will also be pre- and post-fixed making that package utterly useless and then we should work out how to ensure the css loaded in at that specific spot to not use the default css module behaviour.

Am i missing someting here/do you see any other options? Or any thoughts on the two options above?
KoenBrouwer commented 2 years ago

@mjcarsjens @bddjong Hi guys. I made the codesandbox example that is linked in this issue.

In my humble opinion, the biggest drawback of your current approach is the fact that you are using (preprocessed) CSS, which is available in the global scope. Sure, you can namespace things, like you do now with utrecht-heading-1 or BEM-style modifiers, but this will never completely prevent mixing your CSS with your users' defined styles. I couldn't find any research or design decisions on why this approach was chosen, so here's some of my thoughts.

In my role as a Tech Lead at Huishoudboekje, I've compared NL Design System to some other (popular) (React) component libraries some time ago. What I found is that with the current way in which this design system is structured it provides nothing more than a set of global styles. I think that NL Design System's great success could come from an idea where it furnishes a library of ready to use components, where you just import the component and use it, straight out of the box. Let's not call this a design system, but a component library, because that's obviously what NL Design System is trying to become.

The solution here is CSS-in-JS. The big advantage of a CSS-in-JS solution like emotion is that all styles are scoped by default. If you really wish to do so, you could explicitly inject styles into the global scope, but I don't you'll ever need (and want) to do this. It doesn't take away the configurability of your components, in fact, it makes it even easier to "theme" your components. You could just define your colors, your fonts, basically all your CSS-like overrides in a theme file, that will be used in a scoped way in your components. It makes it dead-simple to create your own mobile friendly components, supporting dark mode and many more in a user friendly way.

Take a look at how Chakra UI (based on emotion) does this, and how we take advantage of this theming system at Huishoudboekje. Currently, we only allow to customize the primary and secondary color, but it's very easy to enable customization of any css-property, like fonts, weights, borders, sizes, etc.

Here's some Button-components based on emotion:

I know the feeling - stepping away from plain CSS feels like a big hurdle, steep learning curve etc. - but this is one of those time investment cases of "Once you go $whatever, you never go back". Seriously, as a developer, I wouldn't even consider going back to spending my time on reinventing the wheela button in CSS, trying put two divs side-to-side with display: flex; and margin: 0 auto; and trying to work out a mobile friendly drawer component that slides out of the side of the screen. All of this stuff has been done a 1000 times before and I really rather spend my time adding value to a team and actually making the product.

By the way, I really do realize that overhauling the NL Design System completely to CSS-in-JS would cause a major disruption to the development of your product and in terms of man hours would be a whole seperate long-term project, but I just thought I'd express some opinions from the perspective of a user of your product that I've gathered since I've gotten to know NL Design System, and I hope to have sparked some interest to think a bit outside the box here and focus on what it (as a product) could mean to a developer.

If you want to talk to me a bit more about this, or if you're indeed way, way ahead of me, I'd also like to hear your considerations. Feel free to find me over in the Code4NL Slack. 😉👍🏻