parcel-bundler / lightningcss

An extremely fast CSS parser, transformer, bundler, and minifier written in Rust.
https://lightningcss.dev
Mozilla Public License 2.0
6.35k stars 181 forks source link

Cannot `composeVisitors` with multiple `Rule`s #789

Open oofdere opened 1 month ago

oofdere commented 1 month ago

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)'
                                    }
                                ]
                            }
                        }
                    }
                },
            }
        }
    }]),
});
oofdere commented 1 month ago

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 }
}