I am using React.lazy to load some React classes on runtime so that they are not all loaded at once. My code works for production, but crashes when I am in development mode. (UPDATE: My code no longer works in production - see below).
The particular error message is very cryptic so hard to know exactly what the issue is:
Uncaught TypeError: Cannot read property 'call' of undefined at __webpack_require__ (main.js:64)
The above error occurred in one of your React components:
in Unknown
in Suspense
in div (created by Main)
in Main (created by Route)
in Route (created by App)
in Switch (created by App)
in div (created by App)
in Router (created by BrowserRouter)
in BrowserRouter (created by App)
in App
Consider adding an error boundary to your tree to customize error handling behavior.
Uncaught (in promise) TypeError: Cannot read property 'call' of undefined at __webpack_require__ (main.js:64)
Line 64 gives the following code:
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
I have other React classes that are not having any issues.
The particular class file that I created is called Categories.js. As far as I know I am not loading the class any differently than any of the ones that are working. I have even tried renaming the class/file and have I have also removed most of my data out of it in case something in the file was causing the issue.
Here are the pertinent lines from my code:
import React, {Suspense} from 'react';
....
const Categories = React.lazy(()=> import('./Categories'))
....
return (
<Suspense fallback={<div>Loading...</div>}>
<Categories class_select={class_select} />
</Suspense>
)
If it helps here is my webpack.config.js file:
const HtmlWebPackPlugin = require("html-webpack-plugin");
const CopyPlugin = require('copy-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = (env, argv) => {
const isProduction = (argv.mode === "production")
return {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
plugins: [
"@babel/plugin-syntax-dynamic-import"
]
}
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader"
}
]
}
]
},
...(isProduction && {
optimization: {
// minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
extractComments: 'all',
compress: {
drop_console: true
},
}
})
],
}
}),
devtool: !isProduction && 'eval-source-map',
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
}),
new CopyPlugin([
{ from: 'src/css', to: 'css' }
])
]
};
};
Questions
1) What is causing this error? 2) Why is it only being caused in dev mode but not production mode?
Update
My code no longer works in production either. I am getting the following error:
Uncaught (in promise) TypeError: Cannot read property 'call' of undefined at o (main.js:2).
In fact it is even worse in production than dev. In production none of the React lazy classes are working. In dev it is only one of them that isn't working.
In order to find a potential solution to this issue, I had to tinker with the optimization module, which was indeed the issue here, even when not enabled surprisingly.
My best guess is that some parameters are set to default in production
mode and not in dev
mode and this causes the issues of imports and undefined properties.
I decided to try replicating the deployment environment and check if I could at least "break" the development as well and investigate the issue from here. These are the parameters that are different between production and development and that were suspect in causing the issue at hand (you can try yourself by switching to the opposite value to put your deployment
like the development
environment for example).
On the link I provided in the comment, the user was explaining that the issue was at deployment level and that the way the vendors
chunk were built, were colliding with the main
chunks and cuts the entry
to one another. One of the solution was to use concatenateModules: false
apparently, but to no avail, it didn't solve my issue. So I tried with the others and found the issue bellow.
in module.exports
, the optimization
object should be edited
optimization: {
minimize: true,
namedModules: true,
namedChunks: true,
removeAvailableModules: true,
flagIncludedChunks: true,
occurrenceOrder: false,
usedExports: true,
concatenateModules: true,
sideEffects: false, // <----- in prod defaults to true if left blank
}
Edit: all of these parameters are set to their opposite between production and development, tweak them at your own leisure, some issues stems from them
After switching all the parameters I found that the sideEffects
one is the one that breaks things and I see why:
The sideEffects flag will break down imports into separate ones as follow, as per the documentation on sideEffects:
import { a, b } from "big-module-with-flag"
is rewritten to
import { a } from "big-module-with-flag/a";
import { b } from "big-module-with-flag/b";
And will try to optimize imports accordingly across the modules, which can cause issues in production. Normally this should help optimizing the size of the package by reducing the bundles, at the cost of removing some imports but can break things at import.
I hope the explanation was somewhat clear, if somebody has deeper knowledge on WebPack optimization, any documentation and enhancement would be welcome.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With