Aniket Prajapati
Aniket Prajapati

Reputation: 403

Webpack external react causes React Hooks Error

I am the author of FireJS. I am encountering an issue with react hooks.

(node:21793) UnhandledPromiseRejectionWarning: Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/warnings/invalid-hook-call-warning.html for tips about how to debug and fix this problem.
    at resolveDispatcher (webpack://%5Bname%5D/./node_modules/react/cjs/react.development.js?:1465:13)
    at useState (webpack://%5Bname%5D/./node_modules/react/cjs/react.development.js?:1496:20)
    at Header (webpack://__FIREJS_APP__/./src/pages/404.js?:22:73)
    at processChild (/media/dedsec/Data/Projects/FireJS/node_modules/react-dom/cjs/react-dom-server.node.development.js:3043:14)
    at resolve (/media/dedsec/Data/Projects/FireJS/node_modules/react-dom/cjs/react-dom-server.node.development.js:2960:5)
    at ReactDOMServerRenderer.render (/media/dedsec/Data/Projects/FireJS/node_modules/react-dom/cjs/react-dom-server.node.development.js:3435:22)
    at ReactDOMServerRenderer.read (/media/dedsec/Data/Projects/FireJS/node_modules/react-dom/cjs/react-dom-server.node.development.js:3373:29)
    at Object.renderToString (/media/dedsec/Data/Projects/FireJS/node_modules/react-dom/cjs/react-dom-server.node.development.js:3988:27)
    at /media/dedsec/Data/Projects/FireJS/dist/architects/StaticArchitect.js:51:36
    at default_1.render (/media/dedsec/Data/Projects/FireJS/dist/architects/StaticArchitect.js:57:11)
    at /media/dedsec/Data/Projects/FireJS/dist/FireJS.js:99:143
    at default_1.<anonymous> (/media/dedsec/Data/Projects/FireJS/dist/classes/Plugin.js:20:13)
    at Generator.next (<anonymous>)
    at /media/dedsec/Data/Projects/FireJS/dist/classes/Plugin.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (/media/dedsec/Data/Projects/FireJS/dist/classes/Plugin.js:4:12)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:21793) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2)
(node:21793) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

I've double-checked each and every suggestion given in the help page, but I am unable to resolve the issue.

I am bundling react as an external chunk and then using it as a library. Here's a snapshot of my webpack config;

            target: 'web',
            mode: this.$.config.pro ? "production" : "development",
            entry: {
                "React": "react",
                "ReactDOM": "react-dom",
                "ReactHelmet": "react-helmet",
            },
            output: {
                path: this.$.config.paths.lib,
                filename: "e[contentHash].js",
                library: "[name]",//make file as library so it can be imported for static generation
                libraryTarget: "window"
            }
        mergedConfig.externals["react"] = 'React';
        mergedConfig.externals["react-dom"] = "ReactDOM";
        mergedConfig.externals["react-helmet"] = "ReactHelmet";
        const cssLoaderUse = [MiniCssExtractPlugin.loader,
            {
                loader: 'css-loader',
                options: {
                    modules: {
                        hashPrefix: 'hash',
                    },
                },
            }
        ];
        mergedConfig.module.rules.push({
                test: /\.(js|jsx)$/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ["@babel/preset-env", "@babel/preset-react"]
                    }
                },
            }, {
                test: /\.sass$/i,
                loader: [...cssLoaderUse, 'sass-loader']
            }, {
                test: /\.less$/i,
                loader: [...cssLoaderUse, 'less-loader']
            }, {
                test: /\.css$/i,
                use: cssLoaderUse
            }
        );

I am exporting it as window.__FIREJS_APP__

        mergedConfig.output.library = "__FIREJS_APP__";
        mergedConfig.output.libraryTarget = "window";

The react file I am trying to run

import React, { useState } from 'react';

export default() => {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

Rendering process

runApp: function (func = ReactDOM.render) {
        func(React.createElement(window.__FIREJS_APP__.default, {content: window.__MAP__.content}),
            document.getElementById("root")
        );
    }

if (window.__SSR__)
    LinkApi.runApp(ReactDOM.hydrate)
else
    LinkApi.runApp()

Why do I think this is a webpack issue?

Previously, when I bundled the files normally, React Hooks worked flawlessly but when I switched to external react. React Hooks started to cause this issue.

Upvotes: 5

Views: 2378

Answers (1)

Aniket Prajapati
Aniket Prajapati

Reputation: 403

I figured out how to fix this issue. You need to bundle react, react-dom and react-dom/server to the same bundle.

Eg:

window.React = require("react");
window.ReactDOM = require("react-dom")
window.ReactDOMServer = require("react-dom/server")

Bundle the above file and import it as your first script.

Upvotes: 2

Related Questions