lightningcss
lightningcss copied to clipboard
Support for compiling CSS modules
https://github.com/css-modules/css-modules
- [x] local selectors by default
- [x] local
CustomIdent(e.g. animation names) - [x]
:local(...) - [x]
:global(...) - [ ]
:local(non-function syntax) - [ ]
:global(non-function syntax) - [ ]
:import - [ ]
:export - [ ]
@value - [x]
composesproperty
May not implement @value. It seems like CSS variables have superseded the need for this, and it looks hard to parse since it effects every single property...
:local and :global without function syntax seems like a bad idea... It's not very clear. i.e. :global .foo .bar :local .baz vs .global(.foo .bar) :local(.baz). Most public code I could find used the function syntax, so I'm not going to implement the non-function syntax the first version and we'll see how far we can get with that.
:import and :export are low level features from ICSS, and I couldn't find any public code that used them aside from some integration tests for CSS modules.
Amazing work, congrats on launch! I see CSS modules work is under progress. Any chance providing generateScopedName for custom classnames similar to css-modules? I understand a callback will decrease the performance, however I use it to generate smaller names in production builds:
- reduce css file size
- reduce JS file size as classnames are referenced in it
- prefix classnames with module names (SPA built with individual modules build and deployed separately)
What level of logic do you need? Do you need a full callback that can do anything, or would some kind of templating syntax work for your needs? i.e. "prefix-[name]-[hash]"
Full callback similar to generateScopedName.
Just to elaborate, let say I have an SPA "Fruit" which is divided into multiples modules (separate repos) like Apple, Banana, Cherry etc then I generate minified classnames based on filename (full path) and classname.
A CSS module in Apple
.diffstat-block-deleted, .diffstat-block-added, .diffstat-block-neutral {
display: inline-block;
...
}
will become
.apple_1_1, .apple_1_2, .apple_1_3 {display: inline-block;...}
supporting :local and :global is still useful, especially when using with sass or nesting selector:
:local {
.local-1 .local-2 {
:global {
.global-1 {
color: green;
}
}
}
}
which is normalised to
:local .local-1 .local-2 :global .global-1 {
color: green;
}
would it support different mode like the css-loaders https://webpack.js.org/loaders/css-loader/#mode
reasoning: right now, once set the css-modules flag to be true, all selectors will be added hash, even without specifying :local(), and :local() does not work without turning css-modules flag on.
supporting :local and :global is still useful, especially when using with sass or nesting selector:
hmmm, interesting. I still feel this is a strange syntax though. It works differently from all other css selectors, in that it affects how components to the right are interpreted, and :local/:global do not represent elements at all. This has implications for parsing, which then requires state outside of recursion, raises questions about how nested selectors (e.g. .foo:not(:global .bar) .baz work, and how combinators work (e.g. .foo :global > .bar). With standard selectors, the components are treated independently and each one represents an element in the DOM tree. I am hesitant to support it, but if there is a very compelling use case I'm open to attempting it. I'd just want to be sure that how it should work is fully understood first.
would it support different mode like the css-loaders
do you have a use case in mind for a css module that is global by default? isn't the point of css modules to make the classes locally scoped?
We use nested :global syntax like the following and it looks it doesn't work yet:
.foo {
:global(.bar) {
color:red;
}
}
I expect selector: .foo_XXX .bar { color: red }
That should work, but you need to write the & nesting selector and enable the nesting draft syntax (see readme). example
Wow @devongovett ! Thank you for that hint! I missed that part in README and I was trying to test our real use case to figure out if we can migrate to your superspeed compiler!
May not implement @value. It seems like CSS variables have superseded the need for this, and it looks hard to parse since it effects every single property...
The "import" form like @value moss-green from '@my-company/design-system/colors'; provides a nice mechanism for exposing shared constants (spacing increments, named colors, etc) in a way that you don't have to worry about the potential for global collisions like you would with CSS variables.
100% agreed that @value makes parsing hairy, and supporting the import form would also force resolution of those import paths during processing, so I understand if it's something that never gets supported here, but it does feel like a loss relative to the baseline CSS Modules feature set 🙂
I have been wondering about a way to use CSS vars for the same thing. Maybe a way to enable hashing var names, and referencing/importing them from a different file, but still with the var() syntax so parsing is easier/closer to standard. Vars are also not global and scoped to an element which is nice.
@devongovett Reference/import-able hashed var names seem like they'd be a great way to fill the gap while building on top of platform-native features 👍
I think something along those lines would unlock the ability for the teams I work with to consider migrating to @parcel/css from the PostCSS-based pipeline we use for most projects today. My Rust skills are mediocre at best, but to the degree I could help something like this land I'd be happy to lend a hand 🙂
Yeah I think the main blocker is figuring out what the syntax should be. Possibly something like var(--foo from "./foo.css"), similar to the composes syntax. Could be a bit annoying to write that every time it's referenced, but you could do something like this too, to redeclare locally:
.foo {
--foo: var(--foo from "./foo.css");
}
.bar {
color: var(--foo);
}
@dfreeman fyi, I implemented this syntax here: #183.
@devongovett you may want to add to the docs what CSS Modules features are not supported (@value for example), we chased our tails for few days because of this.
I think that @value is still valuable in cases that don't support variables, like @media queries. Could also implement the alternative environment variables draft for this purpose.