My React app is using Webpack + Babel. When I compile in development everything works perfectly well.
When I bundle for production ("npm run build") and upload the bundle in prod, an error appear in the console:
Why? I found a similar question but didn't find an answer : related stackoverflow question
Here's my webpack.prod.js
config:
const TerserPlugin = require("terser-webpack-plugin");
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { ProvidePlugin, web } = require("webpack");
const cleanPlugin = require("clean-webpack-plugin");
module.exports = {
mode: "production",
devtool: "source-map",
entry: ["regenerator-runtime/runtime.js", "./src/index.js"],
output: {
path: path.resolve(__dirname, "dist"),
filename: "index_bundle.js",
},
module: {
rules: [
{
test: /\.(jsx|js)$/,
exclude: /[\\/]node_modules[\\/]/,
use: {
loader: "babel-loader",
},
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.svg$/,
use: {
loader: "svg-url-loader",
},
},
],
},
resolve: {
alias: { react: path.resolve("./node_modules/react") },
},
plugins: [
new HtmlWebpackPlugin({
template: "src/index.html",
title: "Production",
}),
//no need to import react in every module
new ProvidePlugin({
React: "react",
}),
//erase "dist" bundle before every "npm run build"
new cleanPlugin.CleanWebpackPlugin(),
],
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true,
}),
],
},
};
Package.json:
{
"name": "timerfrontend",
"version": "1.0.0",
"main": "index.js",
"babel": {
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack serve --config webpack.config.js",
"create": "webpack -w",
"build": "webpack --config webpack.prod.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.16.5",
"@babel/preset-env": "^7.16.5",
"@babel/preset-react": "^7.16.5",
"babel-loader": "^8.2.3",
"css-loader": "^6.5.1",
"css-minimizer-webpack-plugin": "^3.3.1",
"html-webpack-plugin": "^5.3.1",
"style-loader": "^3.3.1",
"webpack": "^5.65.0",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^4.7.1"
},
"dependencies": {
"@apollo/client": "^3.5.6",
"@apollo/link-context": "^2.0.0-beta.3",
"@apollo/react-hooks": "^4.0.0",
"@auth0/auth0-react": "^1.8.0",
"apollo-cache-inmemory": "^1.6.6",
"apollo-client": "^2.6.10",
"apollo-link-http": "^1.5.17",
"bootstrap": "^5.0.1",
"clean-webpack-plugin": "^4.0.0",
"dayjs": "^1.10.5",
"npm-force-resolutions": "^0.0.10",
"prop-types": "^15.8.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^6.2.1",
"regenerator-runtime": "^0.13.9",
"svg-url-loader": "^7.1.1",
"terser-webpack-plugin": "^5.3.0",
"webpack-merge": "^5.8.0"
},
"peerDependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"description": "",
"resolutions": {
"react": "17.0.2",
"graphql": "16.1.0"
}
}
The console error point to that index bundle.js:2 code :
The error refer to this react component in my project:
import React, { useEffect } from "react";
import { useMutation } from "@apollo/client";
import { NEW_SESSION, newSessionVariables } from "../../graphql/newSession.js";
import { GET_TOTAL_SESSIONS_TODAY } from "../../graphql/getSessions";
import dayjs from "dayjs";
const sessionCreateDate = dayjs().format("M-D-YYYY");
const TimerAtZero = ({ timerState, toggle, user = { name: "" } }) => {
const [createSession, { data, loading, error }] = useMutation(NEW_SESSION, {
refetchQueries: [
{ query: GET_TOTAL_SESSIONS_TODAY, variables: { sessionCreateDate, userName: user.name } },
],
});
const { endSession } = toggle;
React.useEffect(() => {
if (timerState.seconds === 0 && timerState.minutes === 0) {
endSession();
createSession(newSessionVariables(user.name, timerState));
}
}, [timerState.seconds, timerState.minutes]);
if (loading) return <div>Submitting...</div>;
if (error) return <div>{error.message}</div>;
return null;
};
export default TimerAtZero;
First of all, don't use minified version for finding bugs, it usually shows issues in a weird way that doesn't make sense. Using optimization.minimize = false
in webpack can help with that.
There are cases to look out for when you are using webpack ProvidePlugin
.
The tools that you use for linting, type checking, analyzers, ... should also be configured to detect that global import, which is more work and maintenance in other config files.
For example for eslint
you can do this:
{
"globals": {
"ReactDOM": true
}
}
If you choose to change your bundler someday, then you are gonna have a hard time if the other bundler doesn't support something like ProvidePlugin
.
And also new developers might get confused at first if they didn't know about ProvidePlugin
. But everyone knows about the import
!
Considering these issues, in the end, it's up to you and your project need to see if it's worth using ProvidePlugin
or not.
If you are using ProvidePlugin
only because it's hard to type import react every time, then you need to use snippets in your editor. For example, in VSCode there is a plugin that has this kind of snippets. Or you can create your own snippets if you want.