4

I've made some edits which are listed below.

I am working with a combination of React (18.2.0), Typescript (4.8.4), and Webpack (5.75.0). I am attempting to add some styling to my application, and am trying to use CSS modules. I have tried a few Webpack configurations, and none of them are causing Webpack to use the correct loader. I have tried a few other variants of loaders (as seen in the commented out sections), and none of them are working.

I am using an approach similar to this answer to import the stylesheets (declaring a src/Globals.d.ts, setting the typescript-plugin-css-modules compiler plugin for tsc, and importing as import * as styles from './styles.module.css')

Stylesheet import

import * as styles from './ResultCount.module.css'

export const ResultCount = () => {
  const orders = useSelector((state: ReducedState) => state.all.orders)
  console.log('result count style name', styles.results) // always undefined

  return <p className={styles.results}>

src/Globals.d.ts

declare module '*.module.css'

This is the error that I get, regardless of the loader configuration that I use

cached modules 1.59 MiB (javascript) 27.4 KiB (runtime) [cached] 131 modules
./src/components/Order/styles.module.css 96 bytes [built] [1 error]

ERROR in ./src/components/Order/styles.module.css 1:0
Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> .order {
...

Would someone be able to tell me what I am doing wrong in my webpack.config.ts file?

  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: 'ts-loader',
        options: {
          transpileOnly: true
        },
        exclude: /dist/
      },
      {
        test: /\.css$/,
        use: [
          "style-loader",
          {
            loader: "css-loader",
            options: {
              modules: true,
              importLoaders: 1,
              localIdentName: "[name]_[local]_[hash:base64]",
              sourceMap: true,
              minimize: true
            }
          }
        ]
      },
      // {
      //   test: /\.css$/,
      //   include: path.join(__dirname, 'src/components'),
      //   loader: 'css-loader',
      //   //use: ['style-loader', 'css-loader']
      //   // use: [
      //   //   'style-loader',
      //   //   {
      //   //     loader: 'typings-for-css-modules-loader',
      //   //     options: {
      //   //       modules: true,
      //   //       namedExport: true
      //   //     },
      //   //   },
      //   //   'css-loader',
      //   // ],
      // },
    ]
  },

Edit

I've found out that webpack serve must be restarted for these sorts of changes to take affect (even with reloading turned on). The new issue is: although Webpack successfully builds, but any import of the classes in the .ts files returns an undefined. So none of the styles are applied. I've update the title to reflect the new issue.

What's strange is that my language server (tsserver) can auto complete the classes defined in the .css file from import * as styles from './styles.module.css', but if I console.log() it before I return my TSX, I always see an undefined value. I've confirmed that the mangled CSS modules names are in the final rendered page by finding the inline styles in the browser inspector. I've also tried declaring a styles.module.css.d.ts file (even though I shouldn't need to due to the Typescript plugin) just in case, but that still did not fix the issue. I've also tried (from this answer) to rename from styles.module.css to <component name here>.module.css but that also did not work.

Does anyone know what could be causing this?

3
  • You didn't show the code which actually imports the styles. Also import * as SymbolName and import SymbolName have different semantics. Commented Nov 15, 2022 at 8:04
  • @BillerBuilder edited to provide more code
    – David
    Commented Nov 15, 2022 at 17:26
  • @BillerBuilder changed to import styles from './ComponentNameHere.modules.css and that styles.cssClassNameHere worked. Thanks. Can you resubmit as an answer so I can accept it?
    – David
    Commented Nov 16, 2022 at 2:18

2 Answers 2

3

import * as styles from "module-path"; is semantically different to import styles from "module-path";. Basically don't assume these non-javascript made-up modules follow any advanced module rules and always default import them.

EDIT: This answer is sort of outdated, in that the default way as of version 7.0.0 of css-loader is actually module import, i.e. import * as styles from "module-path"; and in that case styles.default would refer to .default class declaration within the css module file, not the default export of that css-but-actually-js-module. If changing from module import to default import fixes your problem after 2024-04-04, that means you have a dependency problem.

0

npm install --save-dev style-loader css-loader css-modules-dts-loader

and

const isNamedExport = true;
// webpack.config.js
module.exports = {
  // ... other webpack config settings
   module: {
      rules: [
         {
         test: /\.module\.(css|postcss|pcss|scss|sass|less|styl|sss)$/i,
         use: [
               "style-loader",
               {
                  loader: "css-modules-dts-loader",
                  options: {
                     // Convert CSS class names to camelCase (default: false)
                     camelCase: true,
                     // Quote style: "single" or "double" (default: "double")
                     quote: "single",
                     // Indentation style: "tab" or "space" (default: "space")
                     indentStyle: "space",
                     // Number of spaces if indentStyle is "space" (default: 2)
                     indentSize: 2,
                     // Mode: "emit" to generate or "verify" to check the file (default: "emit")
                     mode: isProduction ? "verify" : "emit",
                     // Sort the exported class names alphabetically (default: false)
                     sort: true,
                     // Use named exports instead of interface (default: true)
                     namedExport: isNamedExport,
                     // Custom banner comment at the top of the file
                     banner: "// This file is automatically generated.\n// Please do not change this file!"
                  }
               },
               {
                  loader: "css-loader",
                  options: {
                     sourceMap: true,
                     modules: {
                        namedExport: isNamedExport,
                        exportLocalsConvention: "as-is",
                        localIdentName: "[name]__[local]___[hash:base64]"
                     },
                     importLoaders: 1
                  }
               }
            ]
         }
      ]
   }
};

and import styles by the next way

if isNamedExport is true

import * as styles from "$componentName.module.css"

if isNamedExport is false

import styles from "$componentName.module.css"

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.