How to import SCSS or CSS modules with Typescript, React and Webpack
Asked Answered
D

3

6

I want to use the .scss in my project(bulid with react and typescript),so I use typings-for-css-modules-loader with css-loader and sass-loader.

When I npm run dev, I get this error:

./src/Common.scss
Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed (from ./node_modules/sass-loader/lib/loader.js):

.common {
^
      Invalid CSS after "e": expected 1 selector or at-rule, was "exports = module.ex"

my.scss like this:

.common {
  height: 100px
}

and my wepack.config is:

module.exports = {
    mode: 'development',
    entry: [
        'webpack-dev-server/client',
        path.resolve(root, 'src/index.tsx')
    ],
    devtool: 'inline-source-map',
    devServer: {
        contentBase: './dist',
        publicPath: '/',
        port: 8080,
        historyApiFallback: true
    },
    resolve: {
        extensions: [".ts", ".tsx", ".scss", ".js", ".json", "css"]
    },
    plugins: [
        new CleanWebpackPlugin(['dist']),
        new BundleAnalyzerPlugin(),
        new MiniCssExtractPlugin({
            filename: devMode ? '[name].css' : '[name].[hash].css',
            chunkFilename: devMode ? '[id].css' : '[id].[hash].css',
        })
    ],
    output: {
        filename: 'bundle.js',
        path: path.resolve(root, 'dist'),
        publicPath: '/'
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: 'ts-loader'
            },
            {
                test: /\.(js|jsx)$/,
                use: 'babel-loader',
                exclude: /node_modules/
            },
            {
                test: /\.(sa|sc|c)ss$/,
                use: [{
                    loader: devMode ? MiniCssExtractPlugin.loader : 'style-loader'
                }, {
                    loader: 'css-loader',
                    options: {
                        sourceMap: true,
                        modules: true,
                    }
                }, {
                    loader: 'sass-loader', options: {
                        sourceMap: true
                    }
                }]
            },
            { test: /\.(c|sc)ss$/, loader: 'typings-for-css-modules-loader?modules&sass' },
            {
                test: /\.(jpg|png|gif)$/,
                use: [{
                    loader: 'file-loader',
                    options: {
                        name (file) {
                            if (devMode === 'development') {
                              return '[path][name].[ext]'
                            }

                            return '[hash].[ext]'
                        }
                    }
                }]
            }
        ]
    },
    optimization: {
        splitChunks: {
            chunks: 'all'
        }
    }
};

When I use css-loader with sass-loader or single use typings-for-css-modules-loader, this error is fix.

But I get another error like this:

ERROR in /Users/hly/Bpeanut.github.io/src/app/HeaderBar.tsx
./src/app/HeaderBar.tsx
[tsl] ERROR in /Users/hly/Bpeanut.github.io/src/app/HeaderBar.tsx(40,39)
      TS2339: Property 'header' does not exist on type 'typeof import("/Users/hly/Bpeanut.github.io/src/app/HeaderBar.scss")'.

HeaderBar.tsx like this(the error is here):

import * as styles from './HeaderBar.scss';

class default HeaderBar extends Component {
    render() {
        return(<div className={styles.header}>123</div>)
                                        ^
    }
}

and HeaderBar.scss like:

.header {
    height: 100px;
}

HeaderBar.scss.d.ts:

export interface IHeaderBarScss {
  'header': string;
}

export const locals: IHeaderBarScss;

Now I find another way to fix it.

Use const styles = require('./HeaderBar.scss'); instead of import * as styles from './HeaderBar.scss';

and it work.

thanks.

Dann answered 14/5, 2019 at 14:42 Comment(1)
according to the docs you have to replace css-loader with typings-for-css-modules-loader. Currently you use both which probably causes the error.Endocarditis
I
2

I don't use typings-for-css-modules-loader for my projects with css and scss and with this configuration it works very well :

{
    test: /\.s?css$/,
    use: [
        {
            loader: MiniCssExtractPlugin.loader,
            options: {
                sourceMap: true
            }
        },
        {
        loader: 'css-loader',
            options: {
                sourceMap: true
            }
        },
        {
            loader: 'sass-loader',
            options: {
                sourceMap: true
            }
        }
    ]
},

Does that fix your error?

Imperception answered 14/5, 2019 at 15:2 Comment(4)
thanks. I used the same with you in the past. It can fix this error. But there is another one exposed.Dann
@LoveY.H What is the new one ?Imperception
I wrote it under the webpack.config. It's my fault. thanks.Dann
@LoveY.H All right :) In this case please validate my answerImperception
P
1

Chain the sass-loader with the css-loader and the style-loader to immediately apply all styles to the DOM.

npm install style-loader css-loader sass-loader --save-dev

// webpack.config.js

module.exports = {
    ...
    module: {
        rules: [{
            test: /\.scss$/,
            use: [
                "style-loader", // creates style nodes from JS strings
                "css-loader", // translates CSS into CommonJS
                "sass-loader" // compiles Sass to CSS, using Node Sass by default
            ]
        }]
    }
};

For further information please visit sass loader

Phonoscope answered 14/5, 2019 at 15:11 Comment(0)
T
1

I stumbled upon this question when looking for a way to use CSS modules in my create-react-app project. Therefore, adding the answer for the create-react-app scenario.

The SCSS or CSS module file name should end with module.scss or module.css in order to be able to use in create-react-app projects.

The following example shows a component QuestionForm.tsx and a SCSS module QuestionForm.module.scss working together.

// QuestionForm.tsx

import React, { useState } from 'react';
import style from './QuestionForm.module.scss';

export type PersonalData = {
  name: string;
};

type QuestionFormProps = {
  personalData: PersonalData;
  onChange: (data: PersonalData) => void;
};

export const QuestionForm: React.FC<QuestionFormProps> = ({ personalData, onChange }) => {
  const [name, setName] = useState<string>(personalData.name);

  const handleSubmit = (event: React.FormEvent) => {
    event.preventDefault();
    onChange({ name });
  };

  const handleNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setName(event.target.value);
  };

  return (
    <form className={style.container} onSubmit={handleSubmit}>
      <div className={style.titleWrapper}>
        <h2 className={style.title}>Questionnaire</h2>
      </div>
      <label>
        What is your name?
        <input type="text" minLength={2} maxLength={20} value={name} onChange={handleNameChange} required />
      </label>
      <div className={style.cta}>
        <input className="buttonPrimary" type="submit" value="Submit" />
      </div>
    </form>
  );
};
// QuestionForm.module.scss

@mixin flex($direction: row, $align: center, $justify: center) {
  align-items: $align;
  display: flex;
  flex-direction: $direction;
  justify-content: $justify;
  width: 100%;
}

.container {
  @include flex(column, flex-end, space-evenly);

  border: 1px solid whitesmoke;
  border-radius: 5px;
  height: 230px;
  padding: 0 10px;
  width: 400px;
}

.cta {
  @include flex();
}

.titleWrapper {
  @include flex();
}

.title {
  font-size: 1.5rem;
  font-weight: bold;
}
Tanked answered 11/11, 2021 at 13:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.