0

So during my npm run start it's not catching any changes to the scss files which get compiled into a css file. The scss works just fine when I run npm run build, but it's not catching any css changes. I have added css script, that I would also run off to the side, however, that isn't working either. Do you all have any idea on how to resolve this? Or do you any of you have a working webpack set up that catches scss changes with npm run start?

I actually see the terminal recompile when I make the changes, so I know that it's being caught. This is a react app fyi. Here is my webpack config file (which works during run build)

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
    devtool: 'inline-source-map',

    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: "./index.html"
        }),
        new MiniCssExtractPlugin({
            // Options similar to the same options in webpackOptions.output
            // both options are optional
            filename: "/static/cs/styles.css",
            chunkFilename: "styles.css"
        })


    ],

    entry: './src/index.js',
    output: {
        path: path.join(__dirname, 'build'),
        filename: 'static/js/bundle.js'
    },
    module: {

        rules: [

            {
                test: /\.s?css$/,
                use: [
                    "style-loader",
                    MiniCssExtractPlugin.loader,
                    "css-loader",
                    "sass-loader"
                ]
            },

            {
                use: { loader: 'babel-loader' },
                test: /\.js$/,
                exclude: /node_modules/
            },
            {
                test: /\.(png|svg|jpg|gif)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            outputPath: '',
                        },
                    }

                ]
            },


        ]
    },

    devServer: {

        contentBase: path.join(__dirname, 'build'),

    },


}

And here is my scripts

  "scripts": {
    "start": "webpack-dev-server --mode development --open --hot ",
    "build": "webpack --mode production",
    "build-task:scss-compile": "node-sass-chokidar --source-map true src/scss/ -o dist/css",
    "build-task:autoprefixer": "postcss dist/css/*.css --use autoprefixer -d dist/css",
    "sass:build": "npm-run-all -p build-task:*",
    "sass:watch": "chokidar 'src/styles/*.scss' -c 'npm run sass:build'",
    "dev": "npm-run-all -p sass:*",
    "css": "node-sass src/styles/styles.scss -o dist",
    "css:watch": "npm run css && node-sass src/styles/styles.scss -wo dist"
  },
lakerskill
  • 1,019
  • 1
  • 11
  • 24

2 Answers2

0

First, prepend NODE_ENV=development to your start script:

{
//...
    "start": "NODE_ENV=development webpack-dev-server --mode development --open --hot ",
//...
}

See this answer on StackOverflow to read more about node environment variables.

Now, in production, you want to extract the css out of the created bundle and put it in a separate .css file. In development you want to just inject it inline so you have benefits like hot reloading. In your case, you first extract the css and then try to inject it. Which means that there is nothing to inject anymore by the style-loader because all styles have been extracted already.

Use process.env.NODE_ENV to read which environment you are in (which reads the NODE_ENV value in your npm script). Based on that, add style-loader OR MiniCssExtractPlugin.loader.

        {
            test: /\.s?css$/,
            use: [
                process.env.NODE_ENV === development ?"style-loader": MiniCssExtractPlugin.loader,
                "css-loader",
                "sass-loader"
            ]
        },

Don't forget to only add MiniCssExtractPlugin to your plugins array if you are in a production environment. A way to do this is:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

// Create a shortcut, returns true if you're NODE_ENV is set to development
const isDev = process.env.NODE_ENV === 'development';

// Let's wait with exporting, and first assign the config object to a variable:
const config = {
    // ...    
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            filename: "./index.html"
        }),

    ],
    // ...    
    module: {
        rules: [
            {
                test: /\.s?css$/,
                use: [
                    isDev ? "style-loader" : MiniCssExtractPlugin.loader,
                    "css-loader",
                    "sass-loader"
                ]
            },
        // ...   

        ]
    },
    // ...   
}

// if NOT in development, push `MiniCssExtractPlugin` to plugin array
if (!isDev) {
    config.plugins.push(
        new MiniCssExtractPlugin({
            // Options similar to the same options in webpackOptions.output
            // both options are optional
            filename: "/static/cs/styles.css",
            chunkFilename: "styles.css"
        })
    )
}

module.exports = config;

There are way better ways to split development configuration from production. Many articles - like this one for example - explain ways how to do that.

axm__
  • 2,463
  • 1
  • 18
  • 34
0

This issue resolved for me after running the react-script command with adminitstative permission:

Linux:

sudo npm start

Windows:

Right Click on cmd. Then, click on run as administrator

Mostafa Ghadimi
  • 5,883
  • 8
  • 64
  • 102