developit / microbundle

📦 Zero-configuration bundler for tiny modules.
https://npm.im/microbundle
MIT License
8.04k stars 362 forks source link

Support camelCasing of `styles` when using named imports for CSS modules #877

Closed ovflowd closed 2 years ago

ovflowd commented 3 years ago

When using CSS modules with named imports eg.: import styles from "./MyModule.module.css the IDEs will automatically understand (by the module definition of TypeScript provided within Microbundle) that your keys/properties for styles are in camelCase.

So if in your CSS file you have styles such as .my-style or .my-style__nested-is-cool, TypeScript will by default suggest .myStyle or .myStyle__nestedIsCool even with auto-completion.

This might create confusion during build-time since TypeScript will actually not complain that .myStyle is not a valid property from styles based on the type definition of:

declare module "*.css" {
  const styles: { [className: string]: string };
  export default styles;
}

Which could be re-defined into:

declare module "*.css" {
  type CSSModule<T = string> = Record<string, Extract<T, "string">>;

  const styles: CSSModule;

  export default styles;
}

(I have no idea if the type above actually works)

Still, the issue would possibly persist.

The Bug

If I use microbundle and have CSS classes not in camel-case but using styles.aStyleThatExistsInCamelCase microbundle will actually build the code, make the map of styles eg.: const styles = { "my-non-camel-case": "_HashedClassName" } and having the ´React.createElement(or any other JSX alike) class names using thecamelCase class`.

If I put the correct name but not in camel-case microbundle will do the substitution correctly.

The Idea

Some packages such as https://github.com/gajus/babel-plugin-react-css-modules support replacing the non-camelCase usages into camelCase. So the const styles would become const styles = { "myCamelCaseClass": "_HashedClassName" } even tho the actual original CSS class was, for example, my-camel-case-class.

It would be interesting to add this functionality, since many projects use class names that are not in camel case, and would be supported by having an option --css-modules-to-camel-case for example.

rschristian commented 2 years ago

Sorry for the long time without a reply to this.

TypeScript will by default suggest .myStyle or .myStyle__nestedIsCool even with auto-completion.

That's your editor suggesting strings based on what it's found in the codebase. Not a product of the TS language server. Some editors do try to be smart and convert strings to local syntax (hypenated-class name in CSS to camelCased in JS) but not all; my editor, for example, will happily suggest style.foo-bar-baz in JS despite that being a syntax error. YMMV.

This might create confusion during build-time since TypeScript will actually not complain that .myStyle is not a valid property from styles based on the type definition of:

The only way to get accurate type-checking for CSS modules is to generate a .d.ts file per module, which honestly isn't great. There are tools that do it, but I've found they're pretty slow and create a mess in the source. Here's one such example

It would be interesting to add this functionality, since many projects use class names that are not in camel case, and would be supported by having an option --css-modules-to-camel-case for example.

Ultimately this greatly increases the scope of CSS handling, which we already try to shy away from. I think a suggestion that's more inline with Microbundle's aims would be to write camelCased CSS module classes or be prepared to write a lot of bracket notation to access hyphenated class names.

Going to close this out as it's unlikely to be implemented.