Reputation: 21
I am currently implementing React Router v.4 in an application, where I also use Webpack for bundling. In my webpack config I have set React, ReactDOM and React-router-dom to external dependencies. I import them in my index.html with script-tags. I can't get this approach to work. I am getting the following error from React when I have set the following in externals section in webpack:
externals: {
"react-router": "ReactRouter",
"react-router-dom: "ReactRouterDOM",
"react": "React",
"react-dom": "ReactDOM"}
The error: Invariant Violation: Element type is invalid. expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in.
Everything is exported and that is not the problem. The page worked perfect before I implemented ReactRouter 4. When I did some debugging in Chrome I see that type (and type in this case is a "Router" that is undefined.)
My index looks like this:
import * as React from "react";
import * as ReactDOM from "react-dom";
import { App } from "./main/App";
import {BrowserRouter} from "react-router-dom";
ReactDOM.render((<BrowserRouter><App /></BrowserRouter>), document.getElementById("root"));
If I comment the ReactRouter section in externals it just works, but I want the router as an external global and not bundled in my bundle.js file.
I am unsure how to use the externals section and what to actually write in the fields. Maybe I have wrong names or something? I have tried several different combinations. Fails every time.
Also, my index.html looks like this:
<script src="./node_modules/react/dist/react.js"></script>
<script src="./node_modules/react-dom/dist/react-dom.js"></script>
<script src="./node_modules/react-router/umd/react-router.js"></script>
<script src="./node_modules/react-router-dom/umd/react-router-dom.js"></script>
I'm unsure if I need react-router so I tried both with and without react-router in index.html and externals, no change, fails as usual.
Hope you can help me with this, I have not found any good documentation about externals in webpack 3 that helped me understand why I'm getting this error.
Upvotes: 2
Views: 2914
Reputation: 4609
I think you just need the three entries if you are using the Router in the browser:
externals: {
'react': 'React',
'react-dom': 'ReactDOM',
'react-router-dom': 'ReactRouterDOM'
}
By the way, you may also want to take a look at this Webpack plugin to automate what you are trying to do. Here is a config that I've been using recently with Webpack 4 for development, you may find some pieces of it helpful:
const path = require('path');
const HtmlWebPackPlugin = require("html-webpack-plugin");
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
const WebpackBar = require('webpackbar');
const htmlPlugin = new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html",
hash: true,
});
const externals = [
{
"module": "react",
"entry": "//unpkg.com/react@16/umd/react.production.min.js",
"global": "React"
},
{
"module": "react-dom",
"entry": "//unpkg.com/react-dom@16/umd/react-dom.production.min.js",
"global": "ReactDOM"
},
{
"module": "react-router-dom",
"entry": "//cdnjs.cloudflare.com/ajax/libs/react-router-dom/4.2.2/react-router-dom.min.js",
"global": "ReactRouterDOM"
}
];
module.exports = {
// devtool: 'eval-source-map',
resolve: {
modules: [
"node_modules",
path.resolve(__dirname, "src"),
]
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
retainLines: true,
}
}
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
]
},
plugins: [
new WebpackBar(),
htmlPlugin,
new HtmlWebpackExternalsPlugin({
externals: externals,
}),
],
stats: {
modules: false,
colors: true,
},
};
Upvotes: 3