With the work that's been progressing on styled-components static CSS extraction, we've been inching towards what I could see as a valid, cross-compatible intermediate representation of CSS-in-JS. This isn't what we're doing just yet, but it's what I had in mind to potentially solve all our edge cases:
.foo {
prop: value;
&:pseudo {
foo: bar;
}
}
[
[ SELECTOR_OPEN ],
[ SELECTOR, '.foo' ],
[ PROPERTY, 'prop' ],
[ VALUE, 'value' ],
[ SELECTOR_OPEN ],
[ SELECTOR, '&:psuedo' ],
[ PROPERTY, 'foo' ],
[ VALUE, 'bar' ],
[ SELECTOR_CLOSE ],
[ SELECTOR_CLOSE ],
]
This kind of intermediate representation lends itself to certain optimisations (autoprefixing could happen in-place, for example), as well as fairly compact storage (assuming the keys are some kind of compact Enum). Converting to a string or object representation would be extremely fast and unambiguous, and dynamic values are easily represented:
injectGlobal`
.foo {
color: ${ lighten('black', 0.2) };
${ manyRules };
&:hover, ${ selectorFn } {
foo: bar;
}
}
`
[
[ SELECTOR_OPEN ],
[ SELECTOR, '.foo' ],
[ PROPERTY, 'color' ],
[ VALUE, lighten('black', 0.2) ],
[ DEFERRED, manyRules ],
[ SELECTOR_OPEN ],
[ SELECTOR, '&:hover' ],
[ SELECTOR, selectorFn ],
[ PROPERTY, 'foo' ],
[ VALUE, 'bar' ],
[ SELECTOR_CLOSE ],
[ SELECTOR_CLOSE ],
]
Just a thought, but in my mind this makes static style extraction much more comprehensive, particularly if you could use Prepack or something to figure out that some function calls ( lighten('black', 0.2)
for example) can be evaluated at build time.
The next step would be taking this format and understanding that, say, if a certain class x
, y
and z
only appears in one place, don't define any nested selectors, and yet share certain properties and values, that their CSS could be "atomised" somehow to compact the resulting CSS.
It's been floating around in my head for a while now, thought it might be good to share it around.