javascriptreactjselectronelectron-builderelectron-react

Electron React 404 not found in production


I am building an electron app with react.js. It works fine in development mode but does not work in production mode. I have added the main folder inside the public and you can see my production error in the URL in the main.js code.

My folder structure

enter image description here

My main.js code -

const { app, BrowserWindow, globalShortcut, shell } = require("electron");
const isDev = require("electron-is-dev");
const path = require("path");

const getIconPath = () => {
  let ext = "png";
  if (process.platform === "darwin") {
    ext = "icns";
  }
  if (process.platform === "linux") {
    ext = "png";
  }
  if (process.platform === "win32") {
    ext = "ico";
  }
  let iconPath;
  iconPath = isDev
    ? path.join(__dirname, "..", "assets", "app_icon", `icon.${ext}`)
    : path.join(
        __dirname,
        "..",
        "..",
        "build",
        "assets",
        "app_icon",
        `icon.${ext}`
      );
  return iconPath;
};

let mainWindow;
let splash;
function createWindow() {
  splash = new BrowserWindow({
    width: 600,
    height: 400,
    autoHideMenuBar: true,
    center: true,
    transparent: true,
    frame: false,
    show: false,
    maximizable: false,
    resizable: false,
    minimizable: false,
    alwaysOnTop: true,
  });

  mainWindow = new BrowserWindow({
    minWidth: 500,
    minHeight: 300,
    show: false,
    autoHideMenuBar: true,
    icon: isDev ? getIconPath() : null,
    webPreferences: {
      contextIsolation: false,
      nodeIntegration: true,
    },
  });

  const mainWindowURL = isDev
    ? "http://localhost:3000"
    : `file://${path.join(__dirname, "../", "../build/index.html")}`;

  const splashURL = isDev
    ? "http://localhost:3000/splash"
    : `file://${path.join(__dirname, "../", "../build/index.html#/splash")}`;
  splash.loadURL(splashURL);
  mainWindow.loadURL(mainWindowURL);

  splash.once("ready-to-show", () => {
    splash.show();
  });

  mainWindow.once("ready-to-show", () => {
    setTimeout(() => {
      splash.destroy();
      // maximize the window
      mainWindow.maximize();
      mainWindow.show();
    }, 3000);
  });

  // production a bad jabe
  const handleDevTools = () => {
    if (mainWindow.webContents.isDevToolsOpened()) {
      mainWindow.webContents.closeDevTools();
    } else {
      mainWindow.webContents.openDevTools();
    }
  };
  globalShortcut.register("CommandOrControl+Shift+I", handleDevTools);

  // mainWindow.webContents.openDevTools();

  mainWindow.on("closed", () => {
    mainWindow = null;
  });
}

app.on("ready", createWindow);

app.on("window-all-closed", () => {
  if (process.platform !== "darwin") {
    app.quit();
  }
});

app.on("activate", function () {
  if (BrowserWindow.getAllWindows().length === 0) createWindow();
});

My router.js code with react-router-dom

import Splash from "../pages/Splash/Splash";
import Home from "../pages/Home/Home";
import Login from "../pages/Login/Login";
import Register from "../pages/Register/Register";
import { createBrowserRouter } from "react-router-dom";

const router = createBrowserRouter([
  {
    path: "/",
    children: [
      {
        path: "/",
        element: <Home />,
      },
      {
        path: "/splash",
        element: <Splash />,
      },
      {
        path: "/login",
        element: <Login />,
      },
      {
        path: "/register",
        element: <Register />,
      },
    ],
  },
]);

export default router;

And when I run the project in production mode built by electron-builder. This shows up the

error - Unexpected Application Error! 404 Not Found

enter image description here


Solution

  • Your splash window's url uses a hash (#), yet you use createBrowserRouter. Routing on Electron and React only works with HashRouter, so you should replace createBrowserRouter with createHashRouter.

    Additionally, you might need to write the hash path outside of path.join():

    `file://${path.join(__dirname, "../", "../build/index.html")}#/splash`