1

I made an electron application that manages some simple NeDB databases. When launched from VS Code everything works perfectly, no error and no weird things happening at all. The problem comes after i run npm run package, it creates the output folder as it's supposed to but if i move that folder to a network path and run the .exe it opens up, stays empy for a couple of seconds and then closes without any error.

I checked the folder permissions (even though i created it and had full control over it). I then tried to run the output .exe on my pc and it works fine, i also copied it to another pc and it works there too.

Another weird thing is that after it crashes and I try to delete the folder, i get a message that some files can't be deleting due to them being used in another program, so in order to delete the folder i have to restart my pc because there is nothing in the task manager to kill.

This is my package.json

{
  "name": "gestione-marcature-laser",
  "version": "2.0.0",
  "description": "Gestore Marcature Laser",
  "main": "index.js",
  "scripts": {
    "start": "electron-forge start",
    "package": "electron-forge package",
    "make": "electron-forge make"
  },
  "author": "Nemanja G.",
  "license": "ISC",
  "dependencies": {
    "bcryptjs": "^2.4.3",
    "electron-prompt": "^1.7.0",
    "electron-squirrel-startup": "^1.0.0",
    "jquery": "^3.5.1",
    "moment": "^2.29.1",
    "nedb-async": "^0.1.6",
    "select2": "^4.0.13",
    "xlsx": "^0.16.9"
  },
  "devDependencies": {
    "@electron-forge/cli": "^6.2.1",
    "@electron-forge/maker-deb": "^6.2.1",
    "@electron-forge/maker-rpm": "^6.2.1",
    "@electron-forge/maker-squirrel": "^6.2.1",
    "@electron-forge/maker-zip": "^6.2.1",
    "@electron-forge/plugin-auto-unpack-natives": "^6.2.1",
    "electron": "^25.2.0"
  }
}

This is my forge.config.js

const path = require('path')

module.exports = {
  packagerConfig: {
    icon: './assets/logo',
    asar: {
      //unpack: "**/node_modules/pdf-to-printer/**/*"
    },
    out: "gestione-marcature"
  },
  rebuildConfig: {},
  makers: [
    {
      name: '@electron-forge/maker-squirrel',
      config: {
        iconUrl: path.resolve(__dirname, './assets/logo.ico'),
        setupIcon: path.resolve(__dirname, './assets/logo.ico'),
      },
    },
    {
      name: '@electron-forge/maker-zip',
      platforms: ['darwin'],
    },
    {
      name: '@electron-forge/maker-deb',
      config: {
        icon: './Styles/static/icon.png',
      },
    },
    {
      name: '@electron-forge/maker-rpm',
      config: {},
    },
  ],
  plugins: [
    {
      name: '@electron-forge/plugin-auto-unpack-natives',
      config: {},
    },
  ]
};

and my main.js

const { app, BrowserWindow, dialog } = require('electron');
const path = require('path');
const url = require('url');
const { ipcMain } = require('electron');
const bcrypt = require('bcryptjs');
const prompt = require('electron-prompt');

/* SEZIONE PASSWORD, attualmente quella di sap. Usare codice sotto per generare hash */
/*
const password = "PASS"
const saltRounds = 10

bcrypt.genSalt(saltRounds, function (err, salt) {
    if (err) {
        throw err
    } else {
        bcrypt.hash(password, salt, function (err, hash) {
            if (err) {
                throw err
            } else {
                console.log(hash);
                dialog.showErrorBox('Errore', hash);
                //$2a$10$FEBywZh8u9M0Cec/0mWep.1kXrwKeiWDba6tdKvDfEBjyePJnDT7K
            }
        })
    }
})
*/
//hash = "$2b$10$6OT.h/W3EnHAxiRC15OfR.BdEseDilja8m5Z2LPtEeed3pNYNsJwO";
hash = "$2b$10$OMZlnwGs8av1Kwhbx5ya5uUU2HMCdU.Gyn//s0.J2/mSklzoBEjny";

let win = null;
let win2 = null;

function createWindow() {
    // Create the browser window.
    win = new BrowserWindow({
        width: 1000,
        height: 720,
        webPreferences: {
            nodeIntegration: true,
            preload: path.join(__dirname, 'preload.js')
        },
        icon: path.join(__dirname, './assets/logo.png'),
        show: false
    });

    // maximize it
    win.maximize();

    // and load the index.html of the app.
    win.loadURL(url.format({
        pathname: path.join(__dirname, 'index.html'),
        protocol: 'file:',
        slashes: true
    }));

    win.once('ready-to-show', () => {
        win.show()
    });

    win.on("close", (evt) => {
        //Cancel the current event to prevent window from closing


        //options object for dialog.showMessageBox(...)
        let options = {
            type: "question",
            buttons: ["&Sì", "&No", "&Cancella"],
            defaultId: 2,
            title: "Attenzione!",
            message: "Confermi la chiusura del programma Gestione Database Marcature?",
            detail: "Potrai riaprirlo dall'icona nel desktop.",
            icon: path.join(__dirname, './assets/logo.png'),
            cancelId: 2,
            noLink: true,
            normalizeAccessKeys: true
        };

        let res = dialog.showMessageBoxSync(win, options);
        if (res === 0) {
            //Yes button pressed
        } else if (res === 1) {
            //No button pressed
            evt.preventDefault();
        } else if (res === 2) {
            //Cancel button pressed
            evt.preventDefault();
        }

    });

    // Open the DevTools.
    win.removeMenu();
    //win.webContents.openDevTools();
}

ipcMain.on('openPage', async (_, arg) => {
    if (!win2) {
        let pwd = await prompt({
            title: 'Attenzione!',
            label: 'Inserire la password:',
            type: 'input',
            height: 200,
            inputAttrs: { type: 'password', required: true },
            icon: path.join(__dirname, './assets/logo.png'),
            menuBarVisible: false,
            buttonLabels: 'ok',
            customStylesheet: path.join(__dirname, 'styles', 'prompt-styles.css')
        });

        bcrypt.compare(pwd, hash).then(res => {
            if (res) {
                win2 = new BrowserWindow({
                    parent: win,
                    webPreferences: {
                        nodeIntegration: true,
                        preload: path.join(__dirname, 'preload.js')
                    },
                    frame: false,
                    width: 1000,
                    height: 720,
                    show: false
                });

                win2.maximize();

                win2.loadURL(url.format({
                    pathname: path.join(__dirname, arg.page),
                    protocol: 'file:',
                    slashes: true
                }));

                win2.once('ready-to-show', () => {
                    win2.show()
                });

                win2.on('close', _ => { win2 = null });

                //win2.webContents.openDevTools();
            } else {
                dialog.showErrorBox('Errore', 'Password non corretta!');
            }
        });
    }
});

ipcMain.on('closePage', _ => {
    win2.close();
});

ipcMain.on('showMessageBox', (_, arg) => {
    dialog.showMessageBox({
        title: arg.title,
        message: arg.message
    })
});

const gotTheLock = app.requestSingleInstanceLock();

if (!gotTheLock) {
    app.quit();
} else {
    app.on('second-instance', (event, commandLine, workingDirectory) => {
        // Someone tried to run a second instance, we should focus our window.
        if (win) {
            if (win.isMinimized()) {
                win.restore();
            }
            win.focus();
        }
    })

    // 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.whenReady().then(createWindow);

    // Quit when all windows are closed.
    app.on('window-all-closed', () => {
        // On macOS 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();
        }
    });
}

*** EDIT ***

I tried a few things:

  1. I created another app using npm init electron-app@latest my-app from the electron forge website (https://www.electronforge.io/)
  2. I then run npm run make, put the .exe in a network path and still same issue.
  3. To make sure it wasn't a problem with our server, i shared the folder to another computer and tried to run the .exe and... same issue

Seems like there's something wrong with trying to run an electron executable from a shared folder but can't seem to figure out why

*** EDIT 2 ***

Tried starting the app from terminal, this is the output:

[9836:0726/160545.734:ERROR:gpu_process_host.cc(948)] GPU process launch failed: error_code=18
[9836:0726/160545.780:ERROR:gpu_process_host.cc(948)] GPU process launch failed: error_code=18
[9836:0726/160545.788:ERROR:gpu_process_host.cc(948)] GPU process launch failed: error_code=18
[9836:0726/160545.794:ERROR:gpu_process_host.cc(948)] GPU process launch failed: error_code=18
[9836:0726/160545.799:ERROR:gpu_process_host.cc(948)] GPU process launch failed: error_code=18
[9836:0726/160545.809:ERROR:gpu_process_host.cc(948)] GPU process launch failed: error_code=18
[9836:0726/160545.814:ERROR:gpu_process_host.cc(948)] GPU process launch failed: error_code=18
[9836:0726/160545.819:ERROR:gpu_process_host.cc(948)] GPU process launch failed: error_code=18
[9836:0726/160545.825:ERROR:gpu_process_host.cc(948)] GPU process launch failed: error_code=18
[9836:0726/160545.825:FATAL:gpu_data_manager_impl_private.cc(431)] GPU process isn't usable. Goodbye.
  • What do you expect from `win.removeMenu()` to do? – MfyDev Jul 25 '23 at 20:00
  • `win.removeMenu()` removes the superior menu bar of the application, usually i remove it from my production version. The code above is taken from production so it's uncommented. Of course I tried to comment it and open the dev tools to look for any errors before I wrote this post. – Nemanja Gavranovic Jul 26 '23 at 06:44
  • What OS are you using? – MfyDev Jul 26 '23 at 07:29
  • I'm working on Windows 11 Pro, the shared folder is on a Windows Server 2016. – Nemanja Gavranovic Jul 26 '23 at 07:37
  • If you package the app with `squrirrel`, and run the installer on the shared folder, is the app working correctly? – MfyDev Jul 26 '23 at 07:41
  • Yes, it works without issues. But this is not the ideal solution because it's easier to run the exe from a client and also to update it. Here https://github.com/electron/electron/issues/39227 you can actually see a video of what happens. – Nemanja Gavranovic Jul 26 '23 at 07:56

3 Answers3

1

Folder that Electron.js generates while packaging and which contains all app files and resources is not intended for moving and using. It's used by the electron-forge packager.

Anyways, you can package your app to a portable .exe format using the electron-builder with -p flag for a portable and --win flag for Windows executable:

electron-builder -p --win

To use this module, you'll need to set some things such as publishing provider and updating details.

There are two more alternatives to --win flag:

  • --mac for MacOS
  • --linux for Linux
MfyDev
  • 439
  • 1
  • 12
0

Instead of electron-forge package use:

electron-forge make

Why?

  • Supports forge.config.js file that is not supported by package command
  • More compatibile with distribution (in your case movement to network path)
  • Has more CLI flags (options) than package
MfyDev
  • 439
  • 1
  • 12
  • Hi there thanks for the tip, I actually tried using electron-forge make in the first place but was having the same issue. Running npm run make creates the output folder with the executable and another folder with the setup file. If i put the second folder in the netowork path, it installs the program and it works fine but is not ideal as solution. If I simply try to run the .exe it crashes again without errors. – Nemanja Gavranovic Jul 19 '23 at 07:58
  • @NemanjaGavranovic If you want to move the folder, not installer, you should use `@electron-forge/maker-zip` maker. – MfyDev Jul 19 '23 at 18:12
  • I don't think mobing the folder is an issue, anyways I tried what you suggested. Created a ZIP, moved it to the shared folder, extracted everything and run the .exe. It always closes but the process remains open in the background. :( – Nemanja Gavranovic Jul 20 '23 at 15:22
0

If your app dosn't log any errors to terminal/console, it may mean that the gotTheLock varable is falsy on shared folder. Electon cannot quit properly because of this issue. You need to remove event listeners such as close on all BrowserWindow instances before calling app.quit() for it to quit properly.

MfyDev
  • 439
  • 1
  • 12
  • Thanks, this is correct but the main issue still remains. I used 'electron-log' to log what's happening, and it seems that the renderer process doesn't even start (or there might be an error in the main) but the log doesn't show any errors when the app is launched from a local folder. – Nemanja Gavranovic Jul 25 '23 at 07:58