更新到 webpack 5 后出现运行时错误。类型错误:无法读取未定义的属性(读取"默认")



在将我的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)

我比较了v4和v5 webpack版本之间的Sources选项卡,发现使用此命令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;

和我的包.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"
}
}

我的文件结构看起来像这个

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

  1. config.output.filename中,我更改了CCD_ 2=>'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'
    }),
    
  5. 已将public中的index.html文件重定向到src文件夹,并在HtmlWebpackPlugin中更改了相应的模板。我这么做是因为CopyWebpackPluginHtmlWebpackPlugin之间的文件存在冲突

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

  7. 评论devServer.watchOptions,因为watchOptions密钥不再可用

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

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

感谢您花时间阅读本文,我将感谢您的帮助!

感谢您的回答。在我的案例中,问题是导入类并将其用作类型,出于某种原因,它犯了错误。

我通过更改来修复它

import { UserEntity } from 'models';

import type { UserEntity } from 'models';

在那之后,我的运行时错误消失了

对于我的这个错误版本,问题似乎是我从同一目录中导入了一个webpack中带有别名的文件。

举个例子,我有这样的目录设置:

~/utils (~ is aliased in my webpack)
/fileWithTheImport.ts (
/fileToImport.ts
/index.ts (exports * from the other two files)

我最初使用的是import { named } from ~/utils,并看到了错误。

一旦我将该导入更改为import { named } from './fileToImport.ts',错误就得到了解决,一切如常。

就你而言

我发现它很难读取"default",这对我来说意味着UserEntity的默认导入可能与我遇到的问题类似。

如果UserEntity在同一目录中,我会尝试删除任何别名路径,希望你的问题会消失。

我通过webpack-cli版本升级修复了它

最新更新