'TypeError: MiniCssExtractPlugin is not a constructor

[webpack-cli] TypeError: MiniCssExtractPlugin is not a constructor
    at module.exports (/home/andrey/smartadmin-app/webpack.config.js:70:9)
    at loadConfigByPath (/home/andrey/smartadmin-app/node_modules/webpack-cli/lib/webpack-cli.js:1745:27)
    at async WebpackCLI.loadConfig (/home/andrey/smartadmin-app/node_modules/webpack-cli/lib/webpack-cli.js:1830:30)
    at async WebpackCLI.createCompiler (/home/andrey/smartadmin-app/node_modules/webpack-cli/lib/webpack-cli.js:2185:18)
    at async Command.<anonymous> (/home/andrey/smartadmin-app/node_modules/@webpack-cli/serve/lib/index.js:98:30)
    at async Promise.all (index 1)
    at async Command.<anonymous> (/home/andrey/smartadmin-app/node_modules/webpack-cli/lib/webpack-cli.js:1672:7)

I have got this error and don't understand why it happens. I didn't change any package version and have just done npm install, and I was broken.

{
  "name": "react-typescript",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "view-file": "ts-node --project ts.node.config.json ./webpack/createViewFile.ts",
    "build-dev": "webpack --env mode=development && npm run build-storybook",
    "build-dev-server": "webpack --env mode=development",
    "build-prod": "webpack --env mode=production",
    "lint": "eslint 'client/**'",
    "storybook": "start-storybook -p 5000",
    "build-storybook": "build-storybook -o ./public/storybook",
    "start": "webpack serve --open"
  },
  "dependencies": {
    "axios": "0.24.0",
    "clsx": "1.1.1",
    "dotenv": "8.6.0",
    "react": "17.0.2",
    "react-dom": "17.0.2",
    "react-hook-form": "7.19.5",
    "react-router-dom": "6.0.2",
    "react-string-replace": "0.4.4",
    "webpack-cli": "4.9.1"
  },
  "devDependencies": {
    "@babel/core": "7.16.0",
    "@storybook/addon-actions": "6.4.0-rc.2",
    "@storybook/addon-docs": "6.4.0-rc.2",
    "@storybook/addon-essentials": "6.4.0-rc.2",
    "@storybook/addon-links": "6.4.0-rc.2",
    "@storybook/builder-webpack5": "6.4.0-rc.2",
    "@storybook/manager-webpack5": "6.4.0-rc.2",
    "@storybook/preset-scss": "1.0.3",
    "@storybook/react": "6.4.0-rc.2",
    "@types/express": "4.17.13",
    "@types/node": "16.11.7",
    "@types/react": "17.0.33",
    "@types/react-dom": "17.0.10",
    "@typescript-eslint/eslint-plugin": "5.2.0",
    "@typescript-eslint/parser": "5.2.0",
    "babel-loader": "8.2.3",
    "clean-webpack-plugin": "4.0.0",
    "compression-webpack-plugin": "9.0.0",
    "copy-webpack-plugin": "9.1.0",
    "css-loader": "6.5.1",
    "eslint": "7.32.0",
    "eslint-config-airbnb": "18.2.1",
    "eslint-config-prettier": "8.3.0",
    "eslint-plugin-import": "2.25.2",
    "eslint-plugin-jsx-a11y": "6.4.1",
    "eslint-plugin-prettier": "4.0.0",
    "eslint-plugin-react": "7.26.1",
    "eslint-plugin-react-hooks": "1.7.0",
    "html-webpack-plugin": "5.5.0",
    "mini-css-extract-plugin": "2.4.4",
    "prettier": "2.4.1",
    "sass": "1.43.4",
    "sass-loader": "12.3.0",
    "style-loader": "3.3.1",
    "terser-webpack-plugin": "5.2.4",
    "ts-loader": "9.2.6",
    "ts-node": "10.4.0",
    "typescript": "4.4.4",
    "webpack": "5.64.1",
    "webpack-dev-server": "4.7.3",
    "webpack-manifest-plugin": "4.1.1",
    "webpack-nano": "1.1.1"
  }
}

The command which I execute is npm run start, and my webpack.config.js file is:

require('dotenv').config();

const TerserPlugin = require('terser-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');
const CopyPlugin = require('copy-webpack-plugin');

const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
const { execSync } = require('child_process');

const rules = require('./webpack/rules');
const paths = require('./webpack/paths');
const enviroment = require('./webpack/env');

module.exports = (env) => {
  const isProduction = env.mode === enviroment.PRODUCTION;
  const isDevServer = !!env.WEBPACK_SERVE;

  if (isDevServer) {
    return {
      watch: true,
      mode: enviroment.DEVELOPMENT,
      entry: './src/index.tsx',
      stats: {
        errorDetails: true,
      },
      module: {
        rules: [rules.ts(), rules.css()],
      },
      resolve: {
        extensions: ['.tsx', '.ts', '.js'],
        modules: ['node_modules', 'src'],
      },
      output: {
        filename: 'main.js',
        path: paths.public,
        publicPath: paths.public,
      },
      devServer: {
        port: 8080,
        host: 'localhost',
        static: [paths.public],
        compress: true,
        hot: true,
        headers: {
          'Access-Control-Allow-Origin': '*',
        },
        historyApiFallback: {
          index: '/index.html',
        },
        client: {
          overlay: true,
          logging: 'info',
          progress: true,
        },
        devMiddleware: {
          writeToDisk: true,
        },
      },
      plugins: [
        {
          apply(compiler) {
            compiler.hooks.environment.tap('removePublicFolder', () => {
              execSync('rm -rf public');
            });
          },
        },
        new CompressionPlugin(),
        new MiniCssExtractPlugin({
          filename: isDevServer ? 'main.css' : '[name].[hash].css',
          ignoreOrder: true,
        }),
        new webpack.DefinePlugin({
          'process.env': JSON.stringify(process.env),
        }),
        new WebpackManifestPlugin({
          publicPath: '',
        }),
        new CopyPlugin({
          patterns: [
            { from: paths.views, to: paths.public },
            { from: paths.static, to: paths.public },
          ],
        }),
      ],
    };
  }

  return {
    mode: env.mode,
    entry: './src/index.tsx',
    stats: {
      errorDetails: true,
    },
    ...(isProduction && {
      optimization: {
        minimize: true,
        splitChunks: {
          cacheGroups: {
            vendor: {
              test: /[\\/]node_modules[\\/]/,
              name: 'vendor',
              chunks: 'all',
            },
          },
        },
        minimizer: [
          new TerserPlugin({
            extractComments: false,
          }),
        ],
      },
    }),
    module: {
      rules: [rules.ts(), rules.css()],
    },
    resolve: {
      extensions: ['.tsx', '.ts', '.js'],
      modules: ['node_modules', 'src'],
    },
    output: {
      filename: '[name].[contenthash].js',
      path: paths.public,
      publicPath: '/',
    },
    plugins: [
      {
        apply(compiler) {
          compiler.hooks.environment.tap('removePublicFolder', () => {
            execSync('rm -rf public');
          });
        },
      },
      new CompressionPlugin(),
      new MiniCssExtractPlugin({
        filename: isDevServer ? 'main.css' : '[name].[hash].css',
        ignoreOrder: true,
      }),
      new webpack.DefinePlugin({
        'process.env': JSON.stringify(process.env),
      }),
      new WebpackManifestPlugin({
        publicPath: '',
      }),
      {
        apply(compiler) {
          compiler.hooks.done.tap('done', () => {
            execSync('npm run view-file');
            execSync('ls');
          });
        },
      },
      new CopyPlugin({
        patterns: [{ from: paths.static, to: paths.public }],
      }),
    ],
  };
};

Also I will attach ./webpack/rules.js, to make it clearer:

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const paths = require('./paths');

const css = () => {
  return {
    test: /\.scss$/,
    use: [
      MiniCssExtractPlugin.loader,
      {
        loader: 'css-loader',
        options: {
          modules: true,
        },
      },
      {
        loader: 'sass-loader',
        options: {
          sassOptions: {
            indentWidth: 4,
            includePaths: [paths.styles],
          },
        },
      },
    ],
  };
};

const ts = () => {
  return {
    test: /\.tsx?$/,
    exclude: /node_modules/,
    use: [
      {
        loader: 'ts-loader',
        options: {
          configFile: 'tsconfig.json',
        },
      },
    ],
  };
};

module.exports = {
  ts,
  css,
};


Solution 1:[1]

There is an open issue for this on the create-react-app repository. It looks like this comment has a temporary fix of adding the following to file package.json:

The below works if you're using Yarn:

"resolutions": {
    "mini-css-extract-plugin": "2.4.5"
},

Use the command below for npm:

npm i -D --save-exact [email protected]

Update: As of January 17, it appears that this issue is fixed by mini-css-extract-plugin v2.5.1. You should be able to remove the version pin created above and npm i or yarn install to update.

Solution 2:[2]

For me it was working too and after an update it just stopped working, but as the error suggests, the constructor is undefined, so I changed the way the plugin was called and it worked.

Add '.default' in the call as below:

const MiniCssExtractPlugin = require("mini-css-extract-plugin").default;

Solution 3:[3]

As suggested by Macedo_Montalvão and Sharpek:

You can go to your React project folder.

Then head over to this path:

node_modules\react-scripts\config

Open the webpack.config.js file.

Replace

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

with

const MiniCssExtractPlugin = require('mini-css-extract-plugin').default;

This should work.

Solution 4:[4]

There are breaking changes in this plugin (I think this was by mistake). Here you can read more about this:

The best solution is to change import linked as Macedo_Montalvão said.

const MiniCssExtractPlugin = require("mini-css-extract-plugin").default;

This error was fixed in version 2.5.1.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Peter Mortensen
Solution 3 Peter Mortensen
Solution 4 Peter Mortensen