I am working on a new project using Electron and ReactJS. The project works fine in development mode, but I am trying to create an installer for Windows but no matter what I try and what I find on Google nothing works. I just get a blank white screen.
Below is my pacakge.json
{
"name": "MyApp",
"description": "My App Description",
"version": "0.1.2",
"private": true,
"homepage": "./",
"dependencies": {
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1",
"@types/jest": "^26.0.14",
"@types/node": "^14.11.2",
"@types/react": "^16.9.50",
"@types/react-dom": "^16.9.8",
"bootstrap": "^4.5.2",
"electron-is-dev": "^1.2.0",
"electron-settings": "^4.0.2",
"electron-squirrel-startup": "^1.0.0",
"react": "^16.13.1",
"react-bootstrap": "^1.3.0",
"react-dom": "^16.13.1",
"react-icons": "^3.11.0",
"react-json-pretty": "^2.2.0",
"react-scripts": "3.4.3",
"react-tooltip": "^4.2.10",
"typescript": "^4.0.3"
},
"main": "src/electron-starter.js",
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"electron-start": "set ELECTRON_START_URL=http://localhost:3000 && electron .",
"package-win": "electron-packager . --asar --out=release-builds --platform=win32 --arch=x64 --no-prune --ignore=/e2e --overwrite",
"create-installer-win": "node installers/windows/createInstaller.js"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"electron": "^10.1.3",
"electron-packager": "^12.0.1",
"electron-winstaller": "^4.0.1",
"react-router-dom": "^5.2.0",
"react-toastify": "^6.0.8"
}
}
My electron-start.js script is below
const {electron, Menu, app, BrowserWindow} = require('electron');
// Module to control application life.
//const app = electron.app;
// Module to create native browser window.
//const BrowserWindow = electron.BrowserWindow;
const path = require('path');
const url = require('url');
if (require('electron-squirrel-startup')) app.quit()
// if first time install on windows, do not run application, rather
// let squirrel installer do its work
const setupEvents = require('../installers/setupEvents')
if (setupEvents.handleSquirrelEvent()) {
console.log("Squirrel event returned true");
process.exit()
//return;
}
console.log("Starting main program");
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;
/*const env = process.env.NODE_ENV;
let windowUrlBase = "";
if (env === "production")
{
windowUrlBase = "/";
}
else
{
windowUrlBase = 'http://localhost:3000';
}*/
let windowUrlBase = 'http://localhost:3000';
function returnMainWindow()
{
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
//preload: __dirname + '/preload.tsx'
}
});
//const env = process.env.NODE_ENV;
//console.log("Environment: " + env);
const isDev = require('electron-is-dev');
windowUrlBase = "";
console.log("Not electron dev");
console.log("dir name: " + __dirname);
const startUrl = process.env.ELECTRON_START_URL || url.format({
//pathname: path.join(__dirname, '/../build/index.html'),
pathname: path.join(__dirname, '../index.html'),
protocol: 'file:',
slashes: true,
webSecurity: false
});
mainWindow.loadURL(startUrl);
return mainWindow;
}
function createWindow() {
// Create the browser window.
mainWindow = returnMainWindow();
mainWindow.maximize();
// and load the index.html of the app.
// Open the DevTools.
//mainWindow.webContents.openDevTools();
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
setMainMenu();
}
function setMainMenu()
{
const template = [
{
label: 'File',
submenu: [
{
label: 'Exit',
accelerator: "ctrl+f4",
click() {
app.quit();
}
}
]
},
{
label: 'Edit',
submenu: [
{
label: 'Settings',
click() {
mainWindow.loadURL(windowUrlBase + "/settings");
}
}
]
},
{
label: 'Help',
submenu: [
{
label: 'Show Dev Console',
accelerator: "f11",
click() {
mainWindow.webContents.openDevTools();
}
}
]
}
];
Menu.setApplicationMenu(Menu.buildFromTemplate(template));
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
});
app.on('activate', function () {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
});
My create installer script is below
const createWindowsInstaller = require('electron-winstaller').createWindowsInstaller
const path = require('path')
getInstallerConfig()
.then(createWindowsInstaller)
.catch((error) => {
console.error(error.message || error)
process.exit(1)
})
function getInstallerConfig () {
console.log('creating windows installer')
const rootPath = path.join('./')
const outPath = path.join(rootPath, 'release-builds')
return Promise.resolve({
appDirectory: path.join(outPath, 'crash-catch-control-panel-win32-x64'),
authors: 'Boardies IT Solutions',
noMsi: true,
outputDirectory: path.join(outPath, 'windows-installer'),
exe: 'crash-catch-control-panel.exe',
setupExe: 'crash-catch-control-panel-installer.exe'
//setupIcon: path.join(rootPath, 'assets', 'images', 'logo.ico')
})
}
My setupEvents.js is below
const electron = require('electron')
const app = electron.app
module.exports = {
handleSquirrelEvent: function() {
if (process.argv.length === 1) {
return false;
}
const ChildProcess = require('child_process');
const path = require('path');
const appFolder = path.resolve(process.execPath, '..');
const rootAtomFolder = path.resolve(appFolder, '..');
const updateDotExe = path.resolve(path.join(rootAtomFolder, 'Update.exe'));
const exeName = path.basename(process.execPath);
const spawn = function(command, args) {
let spawnedProcess, error;
try {
spawnedProcess = ChildProcess.spawn(command, args, {detached: true});
} catch (error) {}
return spawnedProcess;
};
const spawnUpdate = function(args) {
return spawn(updateDotExe, args);
};
const squirrelEvent = process.argv[1];
switch (squirrelEvent) {
case '--squirrel-install':
case '--squirrel-updated':
// Optionally do things such as:
// - Add your .exe to the PATH
// - Write to the registry for things like file associations and
// explorer context menus
// Install desktop and start menu shortcuts
spawnUpdate(['--createShortcut', exeName]);
setTimeout(app.quit, 1000);
return true;
case '--squirrel-uninstall':
// Undo anything you did in the --squirrel-install and
// --squirrel-updated handlers
// Remove desktop and start menu shortcuts
spawnUpdate(['--removeShortcut', exeName]);
setTimeout(app.quit, 1000);
return true;
case '--squirrel-obsolete':
// This is called on the outgoing version of your app before
// we update to the new version - it's the opposite of
// --squirrel-updated
app.quit();
return true;
}
}
}
My App.js is below
import * as React from 'react';
import {BrowserRouter, Route, Switch} from 'react-router-dom'
import './Stylesheet.css'
import Dashboard from "./Components/Dashboard";
import Settings from "./Components/Settings";
import './ComponentStyles/BreadcrumbNav.css'
import 'react-toastify/dist/ReactToastify.min.css';
import { ToastContainer, toast } from 'react-toastify';
import CustomerDetails from "./Components/CustomerDetails";
toast.configure({
position: 'top-center',
hideProgressBar: true
});
function App() {
return (
<BrowserRouter>
<div>
<Switch>
<Route path="/" render={() => <Dashboard /> } exact />
<Route path="/customer-information/:customer_id" render={(props) => <CustomerDetails {...props} /> } exact />
<Route path="/settings" render={() => <Settings /> } exact />
</Switch>
</div>
</BrowserRouter>
);
}
export default App;
When I look at the chrome console when the app loads I see the following error:
Not allowed to load local resource: file:///C:/Users/Chris/AppData/Local/MyApp/app-0.1.2/resources/app.asar/index.html
As mentioned above the problem only happens when I launch the electron app when its installed. If I launch it as part of the Node dev server then it works perfectly fine.
UPDATE
Directory structure below as requested
The components directory contains the actual ReactJS components and the directory ComponentStyles are all the individual component stylesheets. The components are typescript so are in tsx format.

