类型错误:MiniCssExtractPlugin不是一个构造函数。

50
[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)

我遇到了这个错误,不明白为什么会出现。我没有改变任何包的版本,只是运行了npm install,结果就出问题了。

{
  "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"
  }
}

我执行的命令是npm run start,我的webpack.config.js文件如下:

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 }],
      }),
    ],
  };
};

还有,我会附上./webpack/rules.js,以使其更清晰明了:

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,
};

猜测一下:我没有看到加载器被使用。可能需要MiniCssExtractPlugin.loader才能使插件构造函数正常工作。 - matthiasgiger
我已经在@matthiasgiger的问题中附加了额外的信息。 - Andrey Radkevich
npm cache clean --force,执行此命令清除缓存;使用此行代码助手,再次重新安装软件包,并在package.json中删除软件包附近的“^”。 - Andrey Radkevich
这里也有完全相同的问题。今天刚注意到,升级了所有包到最新版本后出现了问题。显然是某些东西出了问题,但目前还不确定是什么。我正在使用react-scripts。 - AmateurAardvark
4个回答

50

create-react-app存储库中有一个未解决的问题。看起来这个评论有一个临时修复方法,需要将以下内容添加到文件package.json中:

如果您正在使用Yarn,则以下内容有效:

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

使用以下命令来安装npm:

npm i -D --save-exact mini-css-extract-plugin@2.4.5

更新截至1月17日,似乎mini-css-extract-plugin v2.5.1已经修复此问题。 您应该能够删除上面创建的版本固定并使用npm iyarn install进行更新。


2
  1. 这个问题只适用于Yarn。请查看链接的线程以获取NPM修复方法。
  2. 请务必重新运行 yarn install
- PaulProgrammer
1
@PaulProgrammer FYI,这不是YARN特定的问题,因为我在使用NPM时也遇到了这个问题,而且这个答案解决了它。 - Jeremy Thompson
在我看来,降级软件包并不是一个解决方案。 - Sharpek
1
@Sharpek 这是一个幼稚的回答。如果引入了错误,那么这就是一个完全可行的解决方案。最终他们会修复错误,但在此之前,我认为指定工作版本没有问题。 - PaulProgrammer
这只是一个临时措施,直到下游包(看起来像是react-scripts惹的祸?)修复它们的依赖关系。一旦发生这种情况,请升级。 - samuei

8

对我来说,它以前也可以用,但在更新后就突然无法使用了。但正如错误提示所示,构造函数未定义,因此我改变了插件的调用方式,这样它就可以工作了。

在调用中添加 '.default',如下所示:

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

谢谢,@Macedo。它运行得很好。 - Monzur Alam

7

正如 Macedo_Montalvão Sharpek所建议的:

您可以进入您的React项目文件夹。

然后前往此路径:

node_modules\react-scripts\config

打开webpack.config.js文件。
替换。
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

使用

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

这应该可以工作。


非常感谢您提供的详细步骤!这对我很有帮助。 - LittleLebowski

3

在这个插件中有一些破坏性的变化(我认为这是错误)。您可以在这里阅读更多信息:

最好的解决方案是更改导入的链接,就像Macedo_Montalvão所说的那样。

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

此错误已在2.5.1版本中得到修复。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接