react-router: react-router-dom v5 does not work with electron in production

I’m having an issue using react-router-dom with electron. In development, the router correctly functions and routes users between the different pages. In production, the router no longer functions correctly. In addition to the repo showing the issue, I have some gifs that can quickly outline the problem. Working in development, not working in production.

I am not using redux, and I am using the HashRouter, but I have also tried the MemoryRouter with no luck…

edit I just tested with version 4 of react router dom and it works correctly in production and development. So it seems that this issue is related to version 5.

Version

"electron": "^5.0.0",
"electron-builder": "^20.39.0",
"electron-webpack": "^2.6.2",
"react-router-dom": "^5.0.0"

Test Case

https://github.com/kyle-mccarthy/react-router-dom-electron-issue

Steps to reproduce

The best way to reproduce this error is through the provided github repo.

Expected Behavior

The router should continue to work under the production environment.

Actual Behavior

The router does not correctly work in production.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 34
  • Comments: 30 (2 by maintainers)

Commits related to this issue

Most upvoted comments

Hi Hackers,

The problem with electron and react-router-dom is that electron when working in production mode (not really) is that you with electron are creating an application, (although it is known that it is a scan with js code running in backgroud), electron does not handle history and works with the synchronized URL, BrowseHistory does not work with electron, therefore you must use HashRouter that if you synchronize your URL with a UI that is (windows.location.hash).

This would be your final code for electron and react-router-dom to work perfectly

// Not BrowserHistory, this for pageweb
import { HashRouter, Route } from "react-router-dom";

class App extends Component {
  render() {
    return (
        <HashRouter> 
          <Route exact={true} 
                  path='/'    
                  render={(props) => 
                          <iLogin {...props}/>
                        }
          />
          <Route path='/InitMenu' component={InitMenu}/>
        </HashRouter>
    );
  }
}

This is the solution … it is not a problem of versions

Happy Hacking

Ok, got this sorted:

The issue was that in some places I was importing (IDE did this for me) Link like:

import { Link } from 'react-router-dom/cjs/react-router-dom';

changing it to:

import { Link } from 'react-router-dom';

solves the issue for me.

Just use HashRouter, browser router has too many configurations and will end up breaking your code. Proper way of doing it

import * as React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import { createRoot } from 'react-dom/client'
import {  Routes, Route, HashRouter } from 'react-router-dom'
import Auth from './AuthenticateUser/authPage';
import Load from './LoadScreen/start';

const App = ()=>{
  return(
    <HashRouter>
      <Routes>
        <Route path = "/" element={ <Load/> } />
        <Route path = "auth" element={ <Auth/>} />
      </Routes>
    </HashRouter>
  )
}

Here’s a quick solution that seems to be working for me. Replaced createBrowserHistory with createHashHistory and everything started working again in production electron app.

import { createHashHistory } from "history";
import { Router } from "react-router-dom";

const history = createHashHistory()

const App = () => {
  return (
          <Router history={history}>
            <Main />
          </Router>
  );

The reason might be described in this StackOverflow issue.

I’ve been folllowing this issue as I’ve had a similar problem. I’ve tested in my project and have been able to upgrade to v5.0.0 and the router works in production.

The issue may be that electron-webpack may be breaking react-router-dom in production. You can whitelist react-router-dom to solve this.

Add a electron-webpack.json file containing the following:

{
    "whiteListedModules": ["react-router-dom"]
}

I wasn’t able to get it to work with your demo project, but that might be just a difference in build configuration. I hope this was at least some help to you.

For what it’s worth, here’s my scripts and build config from package.json

{
    "scripts": {
        "dev": "electron-webpack dev",
        "test": "jest",
        "showCoverage": "open coverage/lcov-report/index.html",
        "compile": "electron-webpack",
        "build:mac": "yarn compile && electron-builder --mac --x64",
        "build:win32": "yarn compile && electron-builder --win --ia32"
    },
    "build": {
        "appId": "<my app id>",
        "productName": "<my app name>",
        "directories": {
            "output": "./out/"
        },
        "win": {
            "target": "nsis",
            "asar": false
        },
        "buildVersion": "1.0.0"
    }
}

So I actually stumbled across that which is what led me down this path. In development the (non minified) cjs file works fine, but in production there is an error.

Cannot read property 'exact' of undefined
    at Object.activeStyle (webpack:/node_modules/react-router-dom/cjs/react-router-dom.js:278)

Something equally interesting is that explicitly using “react-router-dom/cjs/react-router-dom.min.js” works in development AND production.

However, while using the normal react-router-dom import I don’t think that the production/minfied version of react-router-dom is ever actually used.

I went and changed back my import to just react-router-dom and then edited the index.js file of react-router-dom to the following

"use strict";

if (process.env.NODE_ENV === "production") {
  console.log("react-router-dom PROD");
  module.exports = require("./cjs/react-router-dom.min.js");
} else {
  console.log("react-router-dom DEV");
  module.exports = require("./cjs/react-router-dom.js");
}

When I run the app in dev I get the expected react-router-dom DEV but I also get react-router-dom DEV in production.

One thing to note is that the electron app doesn’t actually have NODE_ENV set to production while it runs as a bundled app, but it does have the NODE_ENV as production while it is compiling.

It almost makes me think that both versions of react-router-dom are being included.

Helped this answer.

It’s not advisable to use BrowserRouter in electron. Just use HashRouter.

replacing <BrowserRouter> to <HashRouter> should work. 👍

BrowserRouter never worked in electron, everyone mentioned this like 10 times they are using hashrouter, the real solution is what NileDaley said about “whiteListedModules”, if you read documentation https://webpack.electron.build/configuration it says:

White-listing Externals¶ Since webpack is set to target the electron environment, all modules are treated as externals. Unfortunately, there can be a few situations where this behavior may not be expected by some modules. For the case of some Vue UI libraries that provide raw *.vue components, they will needed to be white-listed. This ensures that vue-loader is able to compile them as the UI library originally expected.

so I just added all FE dependencies into whiteListedModules, not just react-router-dom and everything works as expected in production.

It works for me!

I added this at my entry file:

process.env['NODE_' + 'ENV'] = process.env.NODE_ENV

I used Babel to automatically replace the process.env.NODE_ENV to 'production'.

So after compiling, it will become:

process.env['NODE_' + 'ENV'] = 'production'

The react-routr-dom works normally.

My thoughts 🤔

It is possible that incorrect files have been imported or other conditional statements entered in the production due to process.env.NODE_ENV missing.

Most packers, such as Webpack and Parcel, simply replace process.env.NODE_ENV with 'production', but they doesn’t apply the value to the process.env.

Bumping this. My project wasn’t working on production when I had react-router-dom@v5.0.1 installed but works when I downgraded to v4.3.1.

@WilianZilv, Did you solved the issue? HashRouter is not working on my end.

Replacing <Router> with <HashRouter> worked for me. 🎉

@granaber i repeat, nobody used BrowserRouter in Electron ever, everybody are already using HashRouter, and It didn’t work for me with React Router V5 on production nor it worked for the creator of this thread, he had to downgrade to React Router v4… when you whitelist externals, it works with React Router v5…

Top demais @zaynekomichi me salvou aqui em 2023

@WilianZilv, Did you solved the issue? HashRouter is not working on my end.

BrowserRouter never worked in electron, everyone mentioned this like 10 times they are using hashrouter, the real solution is what NileDaley said about “whiteListedModules”, if you read documentation https://webpack.electron.build/configuration it says:

White-listing Externals¶ Since webpack is set to target the electron environment, all modules are treated as externals. Unfortunately, there can be a few situations where this behavior may not be expected by some modules. For the case of some Vue UI libraries that provide raw *.vue components, they will needed to be white-listed. This ensures that vue-loader is able to compile them as the UI library originally expected.

so I just added all FE dependencies into whiteListedModules, not just react-router-dom and everything works as expected in production.

False White-listing Externals, if hashrouter works

I’m also encountering the issue kyle-mccarthy mentioned.

I’ve confirmed the same behavior, that with the latest react router I can run the electron packaged app with NODE_ENV=production and everything works fine. But running it without that will cause all routes to fail.

Their suggested workaround to import from react-router-dom/cjs/react-router-dom worked for me, and I’m able to use that to build working production apps again. (Thanks!)

My relevant dependencies:

"electron": "^5.0.3",
"electron-builder": "^20.43.0",
"electron-compile": "^6.4.2",
"electron-webpack": "^2.6.2",
"react-router-dom": "^5.0.1",