Search code examples
javascriptnode.jsexpresselectronelectron-builder

Express Electron Cannot Require Local Js Files


Before marking as duplicate, I've searched a lot and I couldn't find the answer I need.

I have some issues using express and electron. Everything works fine when I run npm start (start script in package.json is electron .). The problem shows up after building electron using electron-builder. It builds the project for windows x-64 and makes .exe file in the dist folder. Everything look fine until I want to run the executable app. There is this dialog showing up:

Electron Error Dialog

I did a lot of search and I couldn't find out what is wrong. Actual problem is that somehow electron cannot require local js files after building. I tried both asar true and false during build.

Here is my project tree:

 app
 ├── node_modules
 │   └── ...
 ├── Controllers
 │   ├── baseController.js
 │   └── homeController.js
 ├── Database
 │   ├── journals.json
 │   └── users.json
 ├── Models
 │   ├── Journal.js
 │   ├── User.js
 │   └── index.js
 ├── Repository
 │   ├── motor
 │   |   ├── generator.js
 │   |   └── index.js
 │   ├── core
 │   |   └── index.js
 │   ├── init.js
 │   └── index.js
 ├── Views
 │   └── index.html
 ├── www
 │   └── assets
 │       └── images
 │           └── ...
 ├── app.js
 ├── package.json
 ├── package-lock.json
 ├── startup.js
 └── server.js

Here is my app.js:

const path = require('path');
const server = require(path.join(__dirname, 'server'));
const port = 7970;
const electron = require('electron');
const url = require('url');
const { app, BrowserWindow, Menu } = electron;
let index;

// App Ready
app.allowRendererProcessReuse = false;
app.on('ready', function () {
    index = new BrowserWindow({
        webPreferences: {
            nodeIntegration: true,
            nodeIntegrationInWorker: true,
            nodeIntegrationInSubFrames: true,
            contextIsolation: false,
            enableRemoteModule: true
        },
        frame: true,
        minimizable: false,
        maximizable: false,
        fullscreen: false,
        resizable: false,
        movable: true
    });
    index.loadURL(url.format({
        pathname: path.join("localhost:" + port),
        protocol: 'http:',
        slashes: true
    }));
    Menu.setApplicationMenu(null);
});

Here is startup.js where the error actually starts in stack trace:

const path = require('path');
var express = require('express');
var router = express.Router();
var controllers = require(path.join(__dirname, '/Controllers/baseController'));

router.get('/', controllers.home.index)

module.exports = router;

I've already tried require with relative path like require("./whatever") and it did not differ.


Solution

  • Electron is probably not shipping your files with the installation package. Try adding the extraFiles field to your package.json

    So, inside your package.json, and inside your build field, add this:

    build:{
        "appId":"your.product.id",
         ...
        "extraFiles":[
            {
                "from":"Controllers",
                "to":"resources/app/Controllers",
                "filter":["**/*"]
            },
            {
                "from":"Database",
                "to":"resources/app/Database",
                "filter":["**/*"]
            },
            {
                "from":"Models",
                "to":"resources/app/Models",
                "filter":["**/*"]
            },
            {
                "from":"Repository",
                "to":"resources/app/Repository",
                "filter":["**/*"]
            },
            {
                "from":"Views",
                "to":"resources/app/Views",
                "filter":["**/*"]
            },
            {/** You can add more if you need*/}
        ]
    }
    

    Electron, by default, neglects all devDependencies and "new" files when building. The extraFiles field prevents electron-builder from neglecting files that are necessary to your app's execution. It actually ships the files located in the from field into the path in to field. The filter is used to leave some files using an extension or an inside directory if necessary.

    extraFiles has the default path as your app's root directory.