typescript-plugin-css-modules: SCSS - Importing SCSS variables globally breaks exported TS type to `{}`.

Thanks for the awesome TS plugin! 💪

Describe the bug There’s certain cases when using SASS where you need the value of a variable and need to wrap it in #{} in order to get the variable output and not the variable name.

When adding #{} to a *.module.scss, the file’s classNames etc are no longer exported and only shows {} in the TS file.

To Reproduce

Add the following to any *.module.scss file, and try and import it to a TS file.

container.module.scss

@use "variables" as *; // Which includes $breakpoint

.container {
  @media (min-width: #{$breakpoint}) {
    color: red;
  }
}

Expected behavior Using the #{} functionality shouldn’t remove the classNames.

Desktop (please complete the following information):

  • OS: iOS
  • Browser: Chrome
  • Version: 96.

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 16
  • Comments: 17 (1 by maintainers)

Most upvoted comments

@kirill-martynov No and I’m still frustrated by it.

I really want this plugin to work.

@mrmckeb 🙏

me too, we have a lot of media query global variables on a project, but when we are using them, it’s always showing empty type {}

With custom media global variables @media #{$new-tablet-only} { 176881718-b12741af-9858-4183-8d29-7dfc965564cc

Without custom media global variables Screenshot 2022-07-01 at 14 03 32

@mrmckeb please help us to fix this issue

I think it’s related to https://github.com/mrmckeb/typescript-plugin-css-modules/issues/146.

Trying to add the variable directly to the scss fixed the error. I have a SCSS configuration in my NextJS app which includes all my resources, and I think that needs to be set in the same way for the plugin.

const nextConfig = {
  sassOptions: {
      prependData: '@use "libs/theme/src/lib/resources.scss" as *;',
    },
  ...
}

I will try and update the tsconfig plugin settings, and see if I can get it to work 😃

Wow, I’ve been searching this solution for hours. Though I don’t quite enjoy how I need to @use "..." in every module.scss files, it at least doesn’t throw type errors XD. Thank you!

This doesn’t work:

@use 'styles/common` as *;

But this works fine:

@use 'styles/_common` as *;

Adding the underscore before the file name fixed it for me – thank you!

finally could solve it by using _ before partial imports. Basically sass doesn’t need to include the underscore when importing partials but typescript-plugin-css-modules seems not to understand it and requires to include it.

Examples

This doesn’t work:

@use 'styles/common` as *;

But this works fine:

@use 'styles/_common` as *;

as a result, _index.scss files also cannot be detected automatically by this plugin and you need to include the complete file path

CC @mrmckeb

@mrmckeb I can confirm that the following code is now working in my NX monorepo setup.

Thanks for your help and work 💪

Here’s the code if it helps others doing the same setup:

NX Directory structure

...
apps
|-- web
`-- web-e2e
libs
|-- theme
|-- ui
`-- utils
tsconfig.base.json

tsconfig.base.json

{
  "compilerOptions": {
    ...,
    "plugins": [
      {
        "name": "typescript-plugin-css-modules",
        "options": {
          "rendererOptions": {
            "sass": {
              "includePaths": ["libs/**/*.scss"]
            }
          }
        }
      }
    ],
  },
}

apps/web/components/header.tsx

The JSX component including the CSS module files. The styles.header is now correctly shown.

import styles from './header.module.scss';

export const Header = () => {
  return (
    <header className={styles.header}>
        <p>I'm the header</p>
    </header>
  );
};

apps/web/components/header.module.scss

The SCSS file loading the libs/theme.

@use 'libs/theme' as *;

.header {
  .inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 100%;
    padding-right: var(--sz-content-medium);
    padding-left: var(--sz-content-medium);
  }

  @media (min-width: $bp-m) {
    .inner {
      padding-right: var(--sz-content-large);
      padding-left: var(--sz-content-large);
    }
  }
}

libs/theme/index.scss

This includes all the shared SCSS configuration, variables, mixins and functions

$bp-m: 500px;

So, I’ve tried another solutions for my purpose, specially media-quaries global variables. I’ve removed sass variables from my project, switched to pure css modules and installed postcss-custom-media and others plugins

Created a file with custom media queries variables:

// src/styles/media.css

@custom-media --small-viewport (max-width: 30em);

Then I added a postcss.config.js

// postcss.config.js

const postcssCustomMedia = require('postcss-custom-media');
const postcssNested = require('postcss-nested');

module.exports = {
  plugins: [
    postcssNested,
    postcssCustomMedia({
      importFrom: './src/styles/media.css',
    }),
  ],
};

Then I’ve used this variable in my css module file

// main.module.css

.app {
  padding: 0;

  @media (--small-viewport) {
    padding: 10px;
  }
}

And then everything works perfectly: Screenshot 2022-07-01 at 15 18 58