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

using @include in CSS will cause classes to be an empty object #146

Closed
HaiRongHaHA opened this issue Oct 21, 2021 · 24 comments · Fixed by #164
Closed

using @include in CSS will cause classes to be an empty object #146

HaiRongHaHA opened this issue Oct 21, 2021 · 24 comments · Fixed by #164
Assignees
Labels
enhancement New feature or request

Comments

@HaiRongHaHA
Copy link

Hello, when I using @include in CSS will cause classes to be an empty object, as shown in the following figure

image

Just remove @include

image

Maybe it's because mine @mixin is global
// vite.config.ts
image

@xeho91
Copy link

xeho91 commented Nov 15, 2021

I am facing a similar issue.
When a CSS module file contains those "at-rules": @use, @include, and @apply (from the TailwindCSS).

It returns an error Property '<specific class name>' does not exist on type {}.

My tsconfig.json contains the following setup:

"plugins": [
  {
    "name": "typescript-plugin-css-modules",
    "options": {
      "postcssOptions": {
        "useConfig": true // I do use PostCSS (preset-env, and tailwind)
      },
      "rendererOptions": {
        "sass": {
          "includePaths": ["src/styles"] // contains `@mixins` definitions, which are imported with `@use`
        }
      }
    }
  }
]

Sample of CSS module file:

@use "$styles/tools/mixins";

.loader_page {
	position: fixed;
	inset: 0;

	@include mixins.flex-center-column;
	@apply gap-4;

	@include mixins.full;

	& > .loader {
		& .circle_outer {
			@apply text-blue-8;
			@apply fill-current;
		}

		& .circle_inner {
			@apply text-blue-3;
			@apply fill-current;
		}
	}

	& > .message {
		font-size: 1.5em;
	}
}

$styles is a path alias set in tsconfig.json set to src/styles/*.

What I managed to verify so far

  • @apply doesn't seem to be a reason (after commenting them out, the issue still persists)
  • @use is neither a reason for this issue
  • after commenting out @use and @include, the problem is gone, @apply works

EDIT

While I was trying to provide more information, I thought about how not using a path alias "$styles/*": ["src/styles/*]
and replace it with @use "../../styles/tools/mixins";. It works.

Looks like I am using the path aliases configuration incorrectly, and I don't know how to debug it.

@mrmckeb Could I ask for guidance on how I could debug it further?

@kontul-dev
Copy link

I am facing a similar issue as well (using @use).

When I reference some .scss file by relative path, everythig works fine.
image
image

But, when I reference same file absolutely, like this:
image
with tsconfig's "includePaths" set
image

or like that:
image
[FYI: it is possible to reference root dir this way]

I am facing issue described in this thread.
image

Meaning, I have no intellisense with class names, and VSCode shows error (but I can compile code anyway).

@tleunen
Copy link

tleunen commented Nov 30, 2021

So I was able to get it fixed by using an absolute path in includePaths, but it's far from being a great solution.

Can we have someone looking into it? tsconfig cannot be in JS so converting the relative path into an absolute path should be easily doable within this plugin... If that's the right fix.
The tests all use __dirname, which is an absolute path as well, so it could explain why tests are passing, but not for different projects using this sass option includePaths

Looks like some work to transform the relative path into an absolute based on the working directory would be required here

includePaths: [filePath, 'node_modules', ...(includePaths || [])],

cc @mrmckeb

@kontul-dev
Copy link

@tleunen : could you share your solution?

I am not able to make it work (by defining absolute path to "/src").

@tleunen
Copy link

tleunen commented Dec 9, 2021

It's not really a solution though.

I was simply able to make it work by using an absolute path in my tsconfig file.
For example:

"includePaths": ["/Users/xxx/projects/yyy/src"]

@kontul-dev
Copy link

@tleunen Thanks for quick response. I just wanted to try it as temporary solution.

Anyway, I can add another piece of information - it doesn't seem to work on Windows, like:

"includePaths": ["C:\\PROJECTS\\xyz\\src"]

(neither with / as path separator)

@mrmckeb
Copy link
Owner

mrmckeb commented Jan 5, 2022

Sorry for the slow reply, I was moving country (back in Australia now) and obviously that's eaten a lot of my time.

Can someone provide a very simple reproduction for me? I can then use that to debug against and will provide a solution.

@mrmckeb mrmckeb self-assigned this Jan 5, 2022
@mrmckeb mrmckeb added the enhancement New feature or request label Jan 5, 2022
@falahati
Copy link
Contributor

falahati commented Jan 5, 2022

there is a similar problem with less. If the path is specified with a leading slash it fails. Meaning that:

@import "src/themes/_colors.less";
works and VSCode provide type completion inside of the ts file, but VSCode does not offer completion inside of the less file.

but,
@import "/src/themes/_colors.less";
breaks this plugin and therefore the returned import contains {}, but vscode is able to navigate to the imported less file, and variable and code completion works inside of the less file.

So there is no way to have VS work as expected in both files unless a relative path is used which is a pain for styling files.

@falahati
Copy link
Contributor

falahati commented Jan 6, 2022

another interesting fact is that with NextJS, using relative addresses (or absolute without the leading slash) would result in warnings regarding caching issues so even this workaround probably won't work as well as I expected.

I could not find a way to solve this problem with includePaths as some other people claimed to have done with scss so I suppose the situation with less is a little different

@leozhao0709
Copy link

Seeing the similar thing in scss file.

If @import relativePath in scss file, it work correctly. But when it use @import aliasPath (alias path defined in tsconfig file), then it stop working. And intellisense just gives an empty object.

@mthines
Copy link

mthines commented Jan 13, 2022

@mrmckeb

Sorry for the slow reply, I was moving country (back in Australia now) and obviously that's eaten a lot of my time.

Can someone provide a very simple reproduction for me? I can then use that to debug against and will provide a solution.

Look here for examples to reproduce. I wasn't able to get it working properly in a CodeSandbox so you have to try in your own environment.

#152

@tleunen
Copy link

tleunen commented Feb 11, 2022

@mrmckeb Was the info I provided enough for you to be able to test this?
I have sass files which uses "absolute" paths so I can avoid having a relative path hell. I have that setup with my sass loader in webpack as well so it all works great.
Here's an example of a file with import/include statements

@import "sass/mixins/xyz";
.row {
  @include rowContainer;
  // ...
}

The directory sass is at the root of my project.

in my TSconfig, it requires me to put an absolute path, which is not great because the path is different for all devs. Simply using ./ doesn't work.

"rendererOptions": {
  "sass": {
    "includePaths": ["/Users/xxxx/projects/yyyy/"]
  }
}

The ts plugin must ran from the same directory as the sass file, which is why using ./ doesn't work? Anyway to make all of provided custom includePaths relative to the root of the project, or the tsconfig file?
Afaik, tsconfig must be in JSON, so there's no way to use some JS magic to make it work by ourselves.
Another way would be to introduce another option to the plugin, such as rootDir maybe?

@philjones88
Copy link

Also hitting this issue, a bit more complexity to add to the potential solution is supporting TS types:

i.e. in the Foo.module.scss we have:

@import '@/Mixins/Mixins.scss';

.foo {
  @include flex(flex, flex-start, center);

  ......
}

and in our tsconfig.json:

  "paths": {
      "@/*": ["src/*"]
    },

@kirill-martynov
Copy link

Hello!

Does anyone found a solution for this?
Struggling with same issue, when using global scss variables in *.module.scss I'm getting {} empty type
Screenshot 2022-07-01 at 13 57 51

@wp993080086
Copy link

wp993080086 commented Jul 21, 2022

目前在xxx.module.scss中,使用@include是不支持的,会导致获得空对象

以下写法可以:

QQ截图20220721120146
QQ截图20220721120208

QQ截图20220721120244

@PodaruDragos
Copy link

@mrmckeb hello.
my apologies for tagging you like this, but did you happen to have a bit of spare time to merge the PR's that fixes this problem ?

@falahati
Copy link
Contributor

I have pushed an MR to solve this problem with absolute paths. you can check it out before it gets merged (if it ever gets merged) by replacing the current version of the library to:

npm install --save-dev github:falahati/typescript-plugin-css-modules#main --ignore-scripts --no-optional

What it does is that it adds the current .tsconfig directory as the base path of both less and scss renderers. effectively allowing files to be included from the root of the project. This works with my setup using less and NextJs providing IntelliSense both inside the less file and on the tsx file with no warning on the NextJs's webpack compilation process. hope it helps someone.

@tleunen
Copy link

tleunen commented Dec 6, 2022

Hmm.. Thanks @falahati for the fix or tentative fix, but it doesn't seem to fix it for me.
I still have the same behavior as before.

The right output when the scss doesn't contain any @include with absolute paths, and the empty object otherwise

@tleunen
Copy link

tleunen commented Dec 6, 2022

Since it's based automatically on the directory where the tsconfig lives, I don't think this solution works well when the project contains many different tsconfigs files.

But even if I remove or change the abs paths, I can't find any way to make it work.

I think the only good fix for this issue is to fix the includePaths option as I mentioned in this comment

@falahati
Copy link
Contributor

falahati commented Dec 6, 2022

@tleunen, so your project contains multiple .tsconfig files and that's why it doesn't work?

@tleunen
Copy link

tleunen commented Dec 6, 2022

I believe so, but I'm not entirely sure tbh.
I think it makes the file being "compiled" from the closest tsconfig, instead of being compiled from the root project in my case because even if each sub tsconfig inherits from the base one which contains the plugin, each loadPaths would need to be different imo, which is not great. I still can't seem to be able to do this for example and still require to use an absolute path to make it work.

"rendererOptions": {
            "sass": {
              "loadPaths": ["./"]
            }
          }

@falahati
Copy link
Contributor

falahati commented Dec 6, 2022

but adding support for relative addresses still results in the same problem. the relative address has to be resolved against an absolute one and if the absolute address still changes per each tsconfig, then yeah, it is still going to be problematic. Not logically, but definitely in practice.

The problem is that we are trying to replicate the way WebPack resolves files with TS which isn't really ideal.

@tleunen
Copy link

tleunen commented Dec 6, 2022

Ideally, it's resolved based on the absolute path where the config is in, not another tsconfig. Because repeating the following in everyone of them is not ideal. Works, but not ideal.

  "extends": "../tsconfig.base.json",
  "compilerOptions": {
    "plugins": [
      {
        "name": "typescript-plugin-css-modules",
        "options": {
          "rendererOptions": {
            "sass": {
              "loadPaths": ["../"]
            }
          }
        }
      }
    ]
  },

@falahati
Copy link
Contributor

falahati commented Dec 6, 2022

I am not very familiar with the typescript plugin API, but we currently use the ts.server.PluginCreateInfo.getCurrentDirectory() as the base path.

From your description, this returns the directory of each child's tsconfig file instead of the base file. I don't know if there is a way to fix it, or if there is, we really should. this somehow seems like the right behavior to me :)

@mrmckeb

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.