Fork me on GitHub
#shadow-cljs
<
2023-02-03
>
Roman Liutikov09:02:14

Has anyone came up with a decent setup for CSS modules and shadow-cljs? From developer experience side of things Webpack's loaders model is really nice, but I don't want to go that route.

Roman Liutikov09:02:57

Consuming transformed CSS in cljs is not an issue, but I haven't figured yet how to make it work in dev, in watch mode. Where a change to CSS file should trigger recompilation of respective cljs ns. Perhaps emitting JS modules from CSS files is the way to go :thinking_face:

Roman Liutikov10:02:28

On the other hand (:require ["styles.js"]) is kind of confusing

thheller10:02:56

what would you want instead?

Roman Liutikov10:02:34

even (my-require "styles.css") would be fine, as long as the reference is straightforward

thheller10:02:55

please explain what is not straightforward about (:require ["styles.js"])

thheller10:02:11

not sure which problem you are trying to solve here, so please clarify

Roman Liutikov10:02:15

there's no 1to1 mapping if I edit CSS file and require JS file

Roman Liutikov10:02:31

> not sure which problem you are trying to solve here, so please clarify To make the setup less confusing for devs

thheller10:02:50

please give a code example of how to perfect setup would look in your view

thheller10:02:16

I have never used css modules, since I personally fine them very clunky and annoying. so I might be biased and not seeing what a good solution might look like

thheller10:02:41

this is my take on what css should look like https://github.com/thheller/shadow-css

thheller10:02:01

so I need a code example of what another setup would look like

thheller10:02:14

(ns 
  (:require [shadow.css :refer (css)]))

(defn hiccup-example []
  [:div {:class (css :px-4 :shadow {:color "green"})}
   "Hello World"])

thheller10:02:27

how would that look ideally with css modules?

thheller10:02:47

I'm asking about the code side first since that decides how things are implemented and built

Roman Liutikov10:02:42

sure! Will get back in ~30 minutes, after a meeting

Roman Liutikov10:02:48

so ideally it would be the following

(def styles (css "./button.css"))

[:div {:class (:base styles)} ...]
[:div {:class (:warn styles)} ...]

Roman Liutikov10:02:10

maybe (css "./button.js") is fine as a starting point

Roman Liutikov10:02:41

I mean (:require ["button.js"])

hifumi12312:02:34

I’ve tried convincing myself to use garden and inline styling in reagent, but in the end I found all of these “CSS in Clojure” things to be lacking and often requiring me to write literal CSS inside strings, and extensions to garden ultimately felt like I was re-inventing features I took for granted in Sass in a worse way. So in the end I just use Sass for styling and keep a watch running for recompiling Sass assets into CSS (which shadow-cljs transparently hot reloads)

hifumi12312:02:16

As long as you can get a single CSS file outputted by sassc into your public folder, then shadow-cljs takes care of the hot reloading and it works out very nicely in practice. As a benefit you get mixins, color blending functions, scoping, and so on. I cannot see myself ever going back to pure CSS or even what feels like the CLJS equivalent of CSS-in-JSX

hifumi12312:02:26

With that said, if you must use a React library that insists on importing CSS modules, then you have practically no other choice but to set up Webpack (see option #2 https://code.thheller.com/blog/shadow-cljs/2020/05/08/how-about-webpack-now.html)

Roman Liutikov12:02:20

That's what we currently have (a background process smashing all Stylus files together). The main problem is global class names. Which is the only thing really that we want from CSS modules (basically hash + a readable class name).

thheller13:02:13

if you want to do it via a css macro you can do so. but you have to build it yourself. you can inform shadow-cljs that it needs to watch the css files as described here

thheller13:02:28

if you want (:require ["./button.css" :as x]) to work you can also get that

thheller13:02:47

assuming you have a tool that already translates CSS to plain JS

thheller13:02:11

in that case you should add an extra :source-paths entry, something like src/gen

thheller13:02:29

then have your external tool just output the JS files into that folder, while presering namespace structure

thheller13:02:01

so src/main/your/app.css goes to src/gen/your/app.css.js

thheller13:02:31

then as far as shadow-cljs is concerned it is just loading JS files and watch already watches them

thheller13:02:28

bonus points if you can control what kind of JS this outputs, but ESM or CommonJS work. CommonJS just won't hot-reload

thheller13:02:46

ESM is best

thheller09:02:52

I doubt many CLJS people use or even tried css modules. I don't know if there are any tools that just generate the js files directly