Electron – building a desktop application using web technologies

    In this article we will describe what Electron is, how to solve problems with closing the renderer process, how to transfer information from the main process to the renderer process, and how to prevent the launch of more than one instance of Electron application.

    What is Electron

    Electron is an open-source library developed by GitHub which allows developing native graphics applications for desktop operating systems with the use of web technologies: HTML, CSS and JavaScript. Electron achieves this by combining Chromium and Node.js into a single runtime environment, and apps can be built to run on Mac, Windows and Linux.

    It is worth mentioning the advantage given by desktop applications development with Electron – easy creation of a user interface with web technologies and a rich API that allows creation and customization of the application window to suit any needs.

    Let’s look at how Electron application works and what it consists of.

    There are two types of processes in Electron application: main process and renderer process.

    Main process is the process which is started from package.json. A script running in the main process can display the GUI using web pages. In Electron there is always one main process which manages renderer processes.

    The renderer process is responsible for running the user interface of your application or, in other words, a web page being a webContents entity (responsible for rendering and web page managing). All DOM API interfaces, node.js API interfaces and a subset of Electron API libraries are available in this process.

    Solving the problem with rendering process closing

    Due to the multiprocessor architecture of Chromium we faced the problem that at closing or crash during rendering the application continues to run, but nothing is shown in the window (the renderer process is disabled), but we need the renderer process to work continuously.

    The solution to this problem is to capture the ‘crashed’ event (appears when the renderer process is crashed or terminated) for the webContents entity which can be acquired from BrowseWindow (a class which makes it possible to create a browser window).

    Example of application closing at a renderer process crash:

    browseWindow.webContents.on('crashed', () => {
       app.exit()
    })

    Transferring information to the main process from the renderer process

    In Electron some graphic modules (e.g. menu, application window format, size, transparency, etc.) are available only in the main process, but not in the renderer process. Management of these modules from the renderer process is carried out using the ipc module, this module allows sending asynchronous interprocessor messages.

    For more clarity we will demonstrate the call of the main process functionality from the renderer process on the example. When a user presses the exit button, the application should switch to the kiosk mode – a user interface that restricts access to application and system functionality. To solve this task, we use ipcMain and ipcRenderer modules.

    The ipcMain module processes asynchronous and synchronous messages sent from the renderer process in the main process. To do this we will use the on(channel, listener) method, which listens to the channel, and when a new message appears the listener will be called.

    Below is a sample code that listens to the ‘logout’ channel for the appearance of new messages, and when a new message appears it will switch the application to the kiosk mode:

    const {ipcMain} = require('electron');
    ipcMain.on('logout', () => {
       mainWindow.setKiosk(true);
    });

    The ipcRenderer module allows sending asynchronous and synchronous messages from the renderer process to the main process.

    We have implemented the userLogout function which is responsible for the logics of user session termination. Among other things, we will make a signal (send an empty message) about switching of the application to the kiosk mode through the ‘logout’ channel:

    export const userLogout = () => {
       // other logic
       ipcRenderer.send('logout');
    };

    Preventing more than one instance of Electron application from running

    In order to prevent more than one instance of electron-application from running there is the makeSingleInstance method from the app module which returns true if the current application is not a primary instance running, and false if it is primary.

    In OS X the system is configured in such a way that a user cannot run more than one instance of the application. In case of the start of a second instance of the app, it will be closed. However, the single instance mechanism is not working in OS X when a user stars the app from the command line. In order to enforce a single instance of the Electron application in OS X, you need to add the below code to the app. When a second instance starts, it gets blocked, and the system focuses on the running first instance of the Electron application.

    let shouldQuit = app.makeSingleInstance((commandLine, workingDirectory) => {
       if (mainWindow) {
           if (mainWindow.isMinimized()) mainWindow.restore();
           mainWindow.focus();
       }
    });
    if (shouldQuit) {
       app.quit();
       return;
    }

    Conclusion

    Electron is a competitive solution for cross-platform applications development. It does not require knowledge of such programming languages as C++ and Python from the development team, allows you to create applications using the rich capabilities of HTML, CSS, JS and Node.js web technologies.

    The main reason why Electron is so popular: you do not need to rewrite what is already written. Having a ready web application you will not need much effort to transfer it to Electron. Out-of-the-box Electron provides a variety of functions to work with the application window. Another big advantage of the framework is that this project is distributed as an open source and has an active community.

    The main disadvantage of Electron is high RAM consumption and huge size of even the simplest app.