-
Notifications
You must be signed in to change notification settings - Fork 559
Description
The exact structure of the javascript generated from css modules by build tools appears to be somewhat underspecified. Some tools used named exports, some a default export of an object. Many tools offer the ability to transform case to camel or similar. None of these appear to be defined in the spec.
I've found a third bit of variability which is causing me some headache - how to handle composed classes.
Given the CSS file:
.foo {
color: red;
}
.bar {
composes: foo;
background-color: blue;
}Most tools will output something like:
export default {
foo: 'foo_abc123',
bar: 'bar_xyz789 foo_abc123'
}However, this does not play nicely with direct DOM operations.
Firstly, manipulating an HTMLElement's class list (via the DOMTokenList api) requires a list of tokens, each of which must not contain a space characters. As the type information of the above does not contain any clue as to whether the contents do contain a space, instead of being able to just:
$0.classList.add(classes.bar);one is forced to defensively do something like:
$0.classList.add(...classes.bar.split(' '));Secondly, attempting to turn them into valid selectors again only works trivially if you know whether or not they contain spaces -
document.querySelector(`.${classes.bar}`);does not work, but
document.querySelector(`.${classes.bar.replaceAll(' ', '.')}`);does.
I do not expect the spec to suddenly impose specific behaviours on implementers - that horse has well and truly bolted. However, I think it would be of great benefit to document what output options might be considered valid.
I raised this issue with the most excel lent vite-css-modules (privatenumber/vite-css-modules#19) and was quite reasonably told that if it wasn't in the spec it couldn't be unilaterally added to that package. However, as mentioned, also not mentioned in the spec are the export format or case-changing capabilities, both of which have many interpretations.
n.b. in the mean time, for anyone else concerned with this I am currently playing with the horrific workaround of emitting a type for my stub files that looks like this:
declare const styles {
foo: string;
bar: {
split(sep: " "): string[];
}
}which prevents one from accidentally using it as a string. Horrible, but effective.