The Core Parts
An Electron app consists of a few main parts. The basic concept is that you have two or more concurrently running processes. First you have the main process of your application. In this process you have access to NodeJS and thus all your operating system’s power and access to a huge distinct subset of the Electron API. Furthermore the main process creates browser windows. They have one or more render processes and share an important property with your normal browser. These processes are contained in a sandbox. This is because these processes are responsible for rendering the DOM of our web app. Render processes have access to the NodeJS API and a distinct subset of the Electron API, but not to the operating system.
In our projects we used the file dialog to import files from the file system. The allowed properties depend on the operating system. Please check out the API for more details [DIALOG].
We also created custom Electron menu bars for production and development mode. During development we could toggle the developer tools from chromium. For production you can remove that feature from the final Electron app.
To see a full list of all native Electron features, go to [ELECTRON].
“The ipcRenderer module is an instance of the EventEmitter class. It provides a few methods so you can send synchronous and asynchronous messages from the render process (web page) to the main process. You can also receive replies from the main process.” [IPCRENDERER]
In the following example, we register an Event Listener with ipcMain process using the channel name LOAD_FILE_WITH_PATH. Once the Event Listener finishes, we send an event back to the React app. Depending on the result, we add a “success” or “error” to the channel name. This allows us to operate differently with the response inside React [IPCMAIN].
In the React app, we use the ipcRenderer.send to send messages asynchronously to the Event Listener, using the identical channel name. To send messages synchronously use ipcRenderer.sendSync. After that we add a one time listener function for the event using ipc.once. To distinguish IPC calls we add a unique uuid to the Channel name [IPCRENDERER].
To debug the IPC communication between your React application and Electron, you need to install the Electron DevTools Extension.
npm install --save-dev devtron
Afterwards run the following command from the console tab of your application. This will add another tab with the Devtron tools.
Under the Devtron tab you get all kinds of details about your Electron application. Devtron displays all default event listeners from Electron as well as your own custom listeners. Under the IPC link you can record all IPC calls from your application. The Lint tab allows you to do Lint checks and the Accessibility tab checks your web application against the Accessible Rich Internet Applications Suite (ARIA) standard.
Here is an example what the IPC communication in our project looks like.
Remember that we claimed that Electron is the end of the everlasting single-threaded obstacle? Using IPC we can move CPU intensive work to Electron and outsource these tasks using electron-remote. With one single line we can create a task pool that will actually create a new browser window in the background and execute our code (electronFileService.js) in a separate OS process / browser window. Here is an example how to setup the task pool for the file service.
Offline and Storage
When developing an offline desktop application with Electron you have several options on where to store and read data from.
Option 1: Electron / NodeJS
In Electron you can execute NodeJS commands. Therefore you can use almost any module from npmjs.org to read and store data on your local operating system. We recommend this option when you need to persist and process a lot of data.
- SQLite3 (relational database)[SQLITE]
- MongoDB (document database)[MONGODB]
- Neo4J (graph database)[NEO4J]
Option 2: React & Redux / Web Browser
In the second option we persist and process data inside the browser. Modern browsers offer a range of APIs that allow for persisting browser data, i.e. LocalStorage, IndexedDB, SessionStorage, WebSQL and Cookies. We recommend this approach for small datasets that need to be persisted locally. This can be done with any web technology. In our case, the React web application uses Redux as a store for the application state. You can use the redux-persist module to automatically persist the Redux store to the IndexedDB or LocalStorage. In case your web app crashes or you restart the browser, you can configure redux-persist [REDUXP] to automatically rehydrate the Redux Store.
Modern browsers support service worker API to span threads for processing data. If there is information that you need to persist and reuse across restarts, service workers have access to the various browser storage technologies.
Option 3: Combination of Option 1 and 2
There might be times when your desktop client will be online and can retrieve data from a backend server. With our proposed stack you have the full freedom of choosing how to access the backend services. You can either call the backend services via the web application layer (i.e. React WebApp) or you can use the Electron/NodeJS layer. Which way you choose is up to you and might depend on security restrictions or the existence of NodeJS modules you can reuse or other aspects.
Electron is an extremely powerful technology that enables you and your team to create beautiful, responsive, OS independent and maintainable desktop applications. Because there is so much more to Electron, we highly recommend reading https://electronjs.org/docs for the parts that you are interested in or need in your projects. Just keep tuned for our next article.
- [ELECTRON] Electron Docs – https://electronjs.org/docs
- [DEVTRON] – https://github.com/electron/electron/blob/master/docs/tutorial/devtools-extension.md
- [DIALOG] Electron File Dialog – https://github.com/electron/electron/blob/master/docs/api/dialog.md
- [IPCMAIN] – https://github.com/electron/electron/blob/master/docs/api/ipc-main.md
- [IPCRENDERER] – https://github.com/electron/electron/blob/master/docs/api/ipc-renderer.md
- [SQLITE] – https://www.npmjs.com/package/sqlite3
- [MONGODB] – https://www.npmjs.com/package/mongodb
- [NEO4J] – https://www.npmjs.com/package/neo4j
- [REDUXP] – https://github.com/rt2zz/redux-persist
Your job at codecentric?
More articles in this subject area
Discover exciting further topics and let the codecentric world inspire you.