Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Discussion: Support typed css-modules with Typescript #1386

Open
alza54 opened this issue Oct 23, 2019 · 10 comments
Open

Discussion: Support typed css-modules with Typescript #1386

alza54 opened this issue Oct 23, 2019 · 10 comments

Comments

@alza54
Copy link
Contributor

alza54 commented Oct 23, 2019

Hi, I am working on typed Vue css-modules in Typescript support for Nuxt.js.
I saw the issue: nuxt/typescript#35, actually I found this template thanks to this (I am very grateful for this template by the way, this is what I needed but not deserved):]

Yesterday I have had some successes with a custom fork of a css-modules-typescript-loader package:

  1. I extended webpack configuration in nuxt.config.ts build.extend method:
function enableCssModulesPlugin (config): void {
  if (!(config.module && config.module.rules)) { return; }
  for (const rule of config.module.rules) {
    if (!rule.oneOf) { continue; }
    const useLoaders = rule.oneOf.map(e => e.use);
    for (const loaders of useLoaders) {
      const loadersCopy = loaders.map(e => ({ ...e }));
      loadersCopy.map(({ loader }, index) => {
        if (loader === 'css-loader') {
          loaders.splice(index, 0, '@alza54/css-modules-typescript-loader');
        }
        return {};
      });
    }
  }
}
// ...
// enableCssModulesPlugin(config);
  1. I modified Vue.$style augmentation by changing type Readonly<Record<string, string>> to any
  2. In all components I have imported definition file (which exports generated interface of class names)
  3. In all components I have created style computed getter like this:
get style (): cssModules {
  return this.$style;
}

and it kinda worked.

But...

It doesn't make a sense, because types are available after building Webpack modules. Useless.

What will happen when I rename .reload or .actions classes? What if I have a typo there?

Considering that, I suggest trying new approach: extending Typescript configuration instead.
I found that typescript-plugin-css-modules seems to work remarkably good for me:

// test.module.scss
// camelCase for simplicity
$mistyrose: #ffe4e1;

.mistyrose {
  &Background {
    background: $mistyrose;
  }
  &Color {
    color: $mistyrose;
  }
  &Border {
    border: 1px solid $mistyrose;
  }
}

$counts: 'One', 'Two', 'Three';
@each $count in $counts {
  .element#{$count} {
    background: $mistyrose;
  }
}

B9TW3gHlCg

This plugin transforms Sass/SCSS to CSS using sass.renderSync method; I assume that .vue files support could be achieved with a customRenderer function extracting CSS from Vue single file components.

I am just not assured of how to assign exported classes to the $style property yet, though.

I believe this is a proper way of implementing typed Vue CSS modules, unlike extending webpack configuration. I would love to hear your opinion about this @sobolevn 😄

@sobolevn
Copy link
Member

First of all, thanks a lot for your kind words about this project. That's what keeps me motivated to do stuff 🙂

Secondly, about typed css-modules: this sounds really great! I have tried several different options that didn't work. I would be happy to review and merge your PR in case you will find a solution.

Let's start from a PR and go from there 👍

@alza54
Copy link
Contributor Author

alza54 commented Oct 23, 2019

I have no ideas how to pass Vue SFC style tags content into template tag directly, my thoughts include writing SCSS rules for each component in ~/scss and importing them in components files, then overwriting $style property with imported rules

@alza54
Copy link
Contributor Author

alza54 commented Oct 24, 2019

Ok so I tried

import Styles from '~/assets/scss/logo.module.scss';

export default class AppLogo extends Vue {
  get style () {
    return this.$style as typeof Styles;
  }
}

but still IntelliSense is not giving suggestions in template tag, I would need to define the type in module augmentation but it would be different for every compontent ;/ so I don't have any ideas for now..

@sobolevn
Copy link
Member

That's exactly the same problem I had.

@alza54
Copy link
Contributor Author

alza54 commented Oct 24, 2019

Well I guess there is nothing we can do until there is no support from Vue/Nuxt
but maybe a custom TypeScript language service plugin could solve this issue?

@sobolevn
Copy link
Member

maybe a custom TypeScript language service plugin

Sounds complicated 😅
Do you have any experience in this kind of stuff?

@alza54
Copy link
Contributor Author

alza54 commented Oct 24, 2019

unfortunately no:(
but this is how https://github.com/mrmckeb/typescript-plugin-css-modules works

@alza54
Copy link
Contributor Author

alza54 commented Oct 24, 2019

I'll close for now

@alza54 alza54 closed this as completed Oct 24, 2019
@sobolevn
Copy link
Member

Let's keep it open. Because, this feature is so cool to have!

@sobolevn sobolevn reopened this Oct 24, 2019
@StringKe
Copy link

how to support module attr in style tag

<style module lang="scss">
.default-header {
  position: relative;
  height: 65px;
  border-bottom: 1px solid $gray-400;
}
</style>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants