Search code examples
expressasynchronousmongooseelectron

Make ElectronJS mainWindow.loadURL() asynchronous


I have a ExpressJS server running inside an electron instance and the mainWindow.loadURL() is directed to the server view URL (localhost:3000) but the mainWindow launches before the server is able to start so it's not able to fetch the view. I tried restarting the instance once running but apparently it restarts the server too.

I tried stopping the electron instance with a loop for some seconds to give the Express server time to start but is quite a mediocre solution. I need a way to restart the Electron mainWindow using code until it's able to fetch the landing page from the Express server or to stop the Electron instance for as long as the Express server is able to fully start. Note: The Express server also runs a Moongose instance which starts around one second after.

Don't know if the code will help, it's just a common Electron basic index.js file with 2 extra lines:

const {app, BrowserWindow} = require('electron');
const server = require('./app'); // HERE I LOAD THE EXPRESS SERVER

let mainWindow

function createWindow () {
    mainWindow = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
            nodeIntegration: true
        }
    })

    mainWindow.loadURL('http://localhost:3000') // HERE I TRIED TO LOAD THE EXPRESS LANDING PAGE

    mainWindow.on('closed', function () {
        mainWindow = null
    })
}

app.on('ready', createWindow)

app.on('resize', function(e,x,y) {
    mainWindow.setSize(x, y);
});

app.on('window-all-closed', function () {
    if (process.platform !== 'darwin') {
        app.quit()
    }
})

app.on('activate', function () {
    if (mainWindow === null) {
        createWindow()
    }
})

Solution

  • The Express server has facility for a callback with the app.listen() function.

    The callback is called when the Express server is up and running.

    Therefore, you can use that to wrap your window.loadURL(url) function.


    main.js (main process)

    For simplicity, I have added the instantiation of the Express server and the setting of any route(s) to this main.js file.

    // Import required electron modules
    const electronApp = require('electron').app;
    const electronBrowserWindow = require('electron').BrowserWindow;
    
    // Import required Node modules
    const nodeExpress = require('express');
    const nodePath = require('path');
    
    // Start Express server
    const appExpress = nodeExpress();
    
    // Set route(s)
    appExpress.get('/', (req, res) => {
        res.sendFile(nodePath.join(__dirname, 'index.html'));
    });
    
    // Prevent garbage collection
    let window;
    
    function createWindow() {
        window = new electronBrowserWindow({
            x: 0,
            y: 0,
            width: 800,
            height: 600,
            show: false,
            webPreferences: {
                nodeIntegration: false,
                contextIsolation: true,
                preload: nodePath.join(__dirname, 'preload.js')
            }
        });
    
        // Using 'listen' callback, once server is ready, load the URL and show the window.
        appExpress.listen(3000, () => {
            window.loadURL('http://localhost:3000')
                .then(() => { window.show(); });
        });
    
        return window;
    }
    
    electronApp.on('ready', () => {
        window = createWindow();
    });
    
    electronApp.on('window-all-closed', () => {
        if (process.platform !== 'darwin') {
            electronApp.quit();
        }
    });
    
    electronApp.on('activate', () => {
        if (electronBrowserWindow.getAllWindows().length === 0) {
            createWindow();
        }
    });
    

    index.html (render process)

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>Electron Test</title>
            <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';"/>
        </head>
    
        <body>
            <h1>Hello world!</h1>
        </body>
    </html>