lightningcss
lightningcss copied to clipboard
Cannot `composeVisitors` with multiple `Rule`s
trafficstars
The below code outputs .foo{color:red;@light{&{color:green}}@dark{&{color:#ff0}}}. Each rule works on their own, for example if I delete the light rule then the dark rule works: .foo{color:red;@light{&{color:green}}@media (prefers-color-scheme:dark){&{color:#ff0}}}.
let { code, map } = transform({
filename: 'test.css',
minify: true,
code: new TextEncoder().encode('.foo{color: red;@light {color: green;}; @dark {color:yellow;}}'),
customAtRules: {
light: {
prelude: null,
body: 'style-block'
},
dark: {
prelude: null,
body: 'style-block'
}
},
visitor: composeVisitors([{
Rule: {
custom: {
light({ body, loc }) {
return {
type: 'media',
value: {
rules: body.value,
loc,
query: {
mediaQueries: [
{
raw: '(prefers-color-scheme: light)'
}
]
}
}
}
},
}
}
},
{
Rule: {
custom: {
dark({ body, loc }) {
return {
type: 'media',
value: {
rules: body.value,
loc,
query: {
mediaQueries: [
{
raw: '(prefers-color-scheme: dark)'
}
]
}
}
}
},
}
}
}]),
});
For now I'm just using lodash's merge, while it does have pitfalls compared to composeVisitors it's a good temporary solution
export function composePlugins<C extends CustomAtRules>(plugins: (Plugin<C> | Visitor<C>)[]) {
let customAtRules: CustomAtRules = {};
let visitor: Visitor<CustomAtRules> = {};
plugins.forEach(p => {
if ('visitor' in p) {
_.merge(visitor, p.visitor)
if (p.customAtRules) { Object.assign(customAtRules, p.customAtRules) }
} else {
_.merge(visitor, p)
}
});
return { customAtRules, visitor }
}
I've also noticed that composeVisitors drops some specific functions, such as StyleSheet and StyleSheetExit.
composeVisitors([
{
StyleSheet(s) {
console.log(s); // This never gets called
},
StyleSheetExit(s) {
console.log(s); // This never gets called
},
},
{
Rule: {…},
},
{
Rule: {…},
}
])
To work around this, I'm doing my own merging as well. It's not perfect but it works well for simple cases.