Fredrik
Fredrik

Reputation: 21

Problems with ReactRouter 4 when using externals for React,ReactDOM and ReactRouter

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

Answers (1)

AJ Meyghani
AJ Meyghani

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

Related Questions