更新到 webpack 5 后出现运行时错误。 TypeError: Cannot readproperties of undefined (reading 'default')

Dmi*_*min 6 node.js typescript reactjs webpack

将我的 webpack 从 v4 升级到 v5 后,我收到了这个错误,这让我很难调试。

Uncaught TypeError: Cannot read properties of undefined (reading 'default')
    at Module.UserEntity (main.9e5d0727.js:3998)
    at Module.<anonymous> (main.9e5d0727.js:5952)
    at __webpack_require__ (runtime-main.9e5d0727.js:28)
    at fn (runtime-main.9e5d0727.js:308)
    at Module.<anonymous> (main.9e5d0727.js:5645)
    at __webpack_require__ (runtime-main.9e5d0727.js:28)
    at fn (runtime-main.9e5d0727.js:308)
    at Module.<anonymous> (main.9e5d0727.js:4022)
    at __webpack_require__ (runtime-main.9e5d0727.js:28)
    at fn (runtime-main.9e5d0727.js:308)
Run Code Online (Sandbox Code Playgroud)

我比较了 v4 和 v5 webpack 版本之间的“源”选项卡,发现使用此命令生成的文件存在差异cross-env NODE_ENV=local webpack serve --config ./config/webpack.config.js --progress --color

Webpack v4 Webpack v5

这是我当前的webpack.config.js

const path = require('path');
const process = require('process');
const NODE_ENV = process.env.NODE_ENV;

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const RemoveWebpackPlugin = require('remove-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');

const styledComponentsTransformer = require('typescript-plugin-styled-components').default;
const webpack = require('webpack');

const configLocal = require(`./environments/env.local.js`);
const configCommon = require(`./environments/env.common.js`);

const rootPath = process.cwd();
const resolvePath = path.resolve.bind(rootPath);

const production = ['prod', 'production', 'master'].includes(NODE_ENV) ? 'production' : undefined;
const stage = ['staging', 'stage'].includes(NODE_ENV) ? 'staging' : undefined;
const development = ['development', 'dev'].includes(NODE_ENV) ? 'development' : undefined;
const local = 'local';
const ENVIRONMENT = production || stage || development || local;

const STAFF_OAUTH = process.env.STAFF_OAUTH || configLocal.STAFF_OAUTH;
const BACKEND_URL = process.env.BACKEND_URL ? `"${process.env.BACKEND_URL}"` : configLocal.BACKEND_URL;

const environment = {
  ...configCommon,
  ENVIRONMENT: `"${ENVIRONMENT}"`,
  SENTRY_URL: process.env.SENTRY_URL ? `"${process.env.SENTRY_URL}"` : undefined,
  BACKEND_URL,
  STAFF_OAUTH,
  SC_DISABLE_SPEEDY: true
};

const entryPoint = './src/index.tsx';

const config = {
  mode: production || stage ? 'production' : ENVIRONMENT === local ? 'none' : 'development',
  entry: production ? [entryPoint, require.resolve('./ym')] : entryPoint,

  output: {
    path: path.resolve(__dirname, '..', 'build'),
    filename: 'static/js/[name].[fullhash:8].js',
    chunkFilename: 'static/js/[name].[chunkhash:8].js',
    publicPath: '/'
  },

  resolve: {
    extensions: ['.tsx', '.ts', '.js', '.jsx'],
    modules: ['node_modules', resolvePath('src')],
    fallback: { fs: false }
  },

  module: {
    rules: [
      {
        test: /\.tsx?$/,
        include: resolvePath('src'),
        exclude: /node_modules/,
        use: [
          'thread-loader',
          {
            loader: 'ts-loader',
            options: {
              getCustomTransformers: () => ({
                before: [styledComponentsTransformer()]
              }),
              happyPackMode: true,
              transpileOnly: true
            }
          }
        ]
      },
      {
        test: /\.raw\.svg$/,
        use: [
          {
            loader: 'raw-loader',
            options: {
              esModule: false
            }
          }
        ]
      },
      {
        test: /\.(png|svg|jpg|gif)$/,
        exclude: /\.raw\.svg$/,
        loader: 'url-loader',
        options: {
          esModule: false,
          limit: 10000,
          name: 'static/media/[name].[contenthash].[ext]'
        }
      },
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1
            }
          }
        ]
      }
    ]
  },

  optimization: {
    minimize: !!(production || stage),
    minimizer: [new TerserPlugin()],
    runtimeChunk: {
      name: entrypoint => `runtime-${entrypoint.name}`
    },
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    }
  },

  ignoreWarnings: [/export .* was not found in/],

  plugins: [
    // fix "process is not defined" error
    new webpack.ProvidePlugin({
      process: 'process/browser'
    }),
    new CopyWebpackPlugin({
      patterns: [
        {
          from: path.resolve(__dirname, '..', 'public'),
          to: path.resolve(__dirname, '..', 'build')
        }
      ]
    }),
    new HtmlWebpackPlugin({ template: 'src/index.html' }),
    new webpack.DefinePlugin(environment),
    new RemoveWebpackPlugin([path.resolve(__dirname, '..', 'build'), path.resolve(__dirname, '..', '.cache')], 'hide')
  ],

  devServer: {
    static: path.resolve(__dirname, '..'),
    hot: true,
    port: 3000,
    host: 'localhost',
    historyApiFallback: true
    // watchOptions: {
    //   ignored: resolvePath('cypress')
    // }
  },

  performance: {
    hints: false
  }
};

if (ENVIRONMENT === development || ENVIRONMENT === local) {
  config.devtool = 'source-map';
}

if (ENVIRONMENT === local) {
  const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

  config.plugins.push(
    new ForkTsCheckerWebpackPlugin({
      eslint: {
        files: './src/**/*.{ts,tsx,js,jsx}'
      },
      typescript: {
        diagnosticOptions: {
          semantic: true,
          syntactic: true
        }
      }
    })
  );
} else {
  const WorkboxPlugin = require('workbox-webpack-plugin');

  config.plugins.push(
    new WorkboxPlugin.GenerateSW({
      clientsClaim: true,
      skipWaiting: false,
      mode: production || stage ? 'production' : undefined,
      exclude: [/\.map$/, /asset-manifest\.json$/, /LICENSE/]
    })
  );
}

module.exports = config;
Run Code Online (Sandbox Code Playgroud)

和我的package.json文件

{
  "name": "dispatcher-service-front",
  "version": "1.27.0",
  "license": "UNLICENSED",
  "scripts": {
    "cypress:open": "cypress open",
    "start": "cross-env NODE_ENV=local webpack serve --config ./config/webpack.config.js --progress --color",
    "start:ci": "webpack serve --config ./config/webpack.config.js",
    "build": "webpack --config ./config/webpack.config.js",
    "analyze": "webpack --profile --json > stats.json && webpack-bundle-analyzer stats.json"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{ts,tsx}": "eslint -c .eslintrc.staged.js"
  },
  "dependencies": {
    "@types/node": "^16.0.0",
    "@types/react": "^16.14.1",
    "@types/react-dom": "^16.9.13",
    "@types/react-infinite-scroller": "^1.2.1",
    "@types/react-router-dom": "^5.1.5",
    "@types/uuid": "^8.3.1",
    "computed-async-mobx": "^6.1.0",
    "dayjs": "^1.10.6",
    "mobx": "^5.15.4",
    "mobx-react": "^6.2.2",
    "mobx-utils": "^5.5.7",
    "pik-front-utils": "git+https://gitlab+deploy-token-9:p1C2k__vanbHWx_ntuM_@git.pik.ru/pik-software/pik-front-utils.git#semver:1.0.3",
    "pik-ui-kit": "git+https://gitlab+deploy-token-8:gqgws4edpujq2MyATRR7@git.pik.ru/pik-software/pik-ui-kit.git#semver:1.10.3",
    "process": "^0.11.10",
    "react": "^16.14.0",
    "react-dom": "^16.14.0",
    "react-infinite-scroller": "^1.2.4",
    "react-is": "^17.0.2",
    "react-router-dom": "^5.2.0",
    "reflect-metadata": "^0.1.13",
    "sanitize.css": "^12.0.1",
    "serializr": "^2.0.5",
    "styled-components": "^5.2.1",
    "typescript": "^4.3.0",
    "typescript-ioc": "^3.2.2",
    "uuid": "^8.3.2"
  },
  "devDependencies": {
    "@types/styled-components": "^5.1.11",
    "@typescript-eslint/eslint-plugin": "^4.28.2",
    "@typescript-eslint/parser": "^4.28.2",
    "copy-webpack-plugin": "^9.1.0",
    "cross-env": "^7.0.2",
    "css-loader": "^6.5.1",
    "cypress": "^8.6.0",
    "cypress-file-upload": "^5.0.8",
    "eslint": "^7.30.0",
    "eslint-plugin-cypress": "^2.11.3",
    "eslint-plugin-import": "^2.23.4",
    "eslint-plugin-jsdoc": "^35.4.1",
    "eslint-plugin-prefer-arrow": "^1.2.3",
    "eslint-plugin-react": "^7.24.0",
    "eslint-plugin-react-hooks": "^4.2.0",
    "file-loader": "^6.2.0",
    "fork-ts-checker-webpack-plugin": "^6.4.0",
    "html-webpack-plugin": "^5.5.0",
    "husky": "^4.3.8",
    "lint-staged": "^11.0.0",
    "raw-loader": "^4.0.2",
    "remove-webpack-plugin": "^1.2.2",
    "style-loader": "^3.3.1",
    "terser-webpack-plugin": "^5.2.5",
    "thread-loader": "^3.0.4",
    "ts-loader": "^9.2.6",
    "typescript-plugin-styled-components": "^2.0.0",
    "url-loader": "^4.1.1",
    "webpack": "^5.64.0",
    "webpack-bundle-analyzer": "^4.5.0",
    "webpack-cli": "^4.9.1",
    "webpack-dev-server": "^4.5.0",
    "workbox-webpack-plugin": "^6.4.1"
  }
}
Run Code Online (Sandbox Code Playgroud)

我的文件结构如下

我根据webpack 5 迁移指南更改了一些内容

  1. config.output.filename中我改变了 'static/js/[name].[hash:8].js'=>'static/js/[name].[fullhash:8].js'

  2. config.output.resolve中删除node: { fs: 'empty' }并添加fallback: { fs: false }

  3. stats.warningFilter重命名为ignoreWarnings

  4. 添加此插件以修复“进程未定义”错误

     new webpack.ProvidePlugin({
       process: 'process/browser'
     }),
    
    Run Code Online (Sandbox Code Playgroud)
  5. 将index.html文件从public重定向到src文件夹,并更改HtmlWebpackPlugin. CopyWebpackPlugin我这样做是因为此文件之间存在冲突HtmlWebpackPlugin

  6. devServer.contentBase重命名为devServer.static

  7. 现在评论了devServer.watchOptionswatchOptions ,因为密钥不再可用

  8. 删除了两个插件new webpack.HotModuleReplacementPlugin()new HardSourceWebpackPlugin({ cacheDirectory: path.resolve(__dirname, '..', '.cache')

就是这样。另外,我比较了 v4 和 v5 版本之间的文件构建方式webpack --config ./config/webpack.config.js,发现根本没有区别!除了在index.html文件中脚本标签被移动到<head>

感谢您花时间阅读本文,我将不胜感激任何帮助!