Fork me on GitHub
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


what would you want instead?

Roman Liutikov10:02:34

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


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


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


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


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


this is my take on what css should look like


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


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

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


how would that look ideally with css modules?


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"])


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)


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


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

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).


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


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


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


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


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


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


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


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


ESM is best


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