wemake-services / wemake-vue-template

Bleeding edge vue template focused on code quality and developer happiness.
https://wemake-services.gitbook.io/wemake-vue-template/
MIT License
732 stars 72 forks source link

Discussion: Support typed css-modules with Typescript #1386

Open alza54 opened 5 years ago

alza54 commented 5 years ago

Hi, I am working on typed Vue css-modules in Typescript support for Nuxt.js. I saw the issue: https://github.com/nuxt/typescript/issues/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);
  2. I modified Vue.$style augmentation by changing type Readonly<Record<string, string>> to any
  3. In all components I have imported definition file (which exports generated interface of class names)
  4. 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 commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

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 commented 5 years ago

That's exactly the same problem I had.

alza54 commented 5 years ago

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 commented 5 years ago

maybe a custom TypeScript language service plugin

Sounds complicated šŸ˜… Do you have any experience in this kind of stuff?

alza54 commented 5 years ago

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

alza54 commented 5 years ago

I'll close for now

sobolevn commented 5 years ago

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

StringKe commented 4 years ago

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>