Building Desktop Apps With Electron
Published: 2023-10-13 16:19:32

by [Akinsanmi Gideon](https://blog.openreplay.com/authors/akinsanmi-gideon)

<blockquote><em>
Electron is a powerful and popular open-source framework that revolutionizes how desktop applications are built. By combining the strengths of web technologies such as HTML, CSS, and JavaScript with the versatility of Node.js, Electron empowers developers to easily create cross-platform desktop applications. Its robust capabilities have attracted hundreds of tech companies, making it the go-to choice for crafting modern and feature-rich desktop experiences. This article will delve into the world of Electron, exploring its architecture, benefits, and how it has transformed the landscape of desktop app development.
</em></blockquote>

<div style="background-color:#efefef; border-radius:8px; padding:10px; display:block;">
<hr/>
<h3><em>Session Replay for Developers</em></h3> 
<p><em>Uncover frustrations, understand bugs and fix slowdowns like never before with <strong><a href="https://github.com/openreplay/openreplay" target="_blank">OpenReplay</a></strong> — an open-source session replay suite for developers. It can be <strong>self-hosted</strong> in minutes, giving you complete control over your customer data.</em></p>
<img alt="OpenReplay" style="margin-top:5px; margin-bottom:5px;" width="768" height="400" src="https://raw.githubusercontent.com/openreplay/openreplay/main/static/openreplay-git-hero.svg" class="astro-UXNKDZ4E" loading="lazy" decoding="async">
<p><em>Happy debugging! <a href="https://openreplay.com" target="_blank">Try using OpenReplay today.</a></em><p>
<hr/>
</div>

[Electron](https://www.electronjs.org/docs/latest/), an immensely popular open-source library, enjoys extensive usage, boasting more than 650k weekly downloads on [npm](https://www.npmjs.com/package/electron) and an impressive 100k stars on [GitHub](https://github.com/electron/electron). It is a robust tool for constructing versatile desktop applications that seamlessly operate across multiple platforms, including Windows, Mac, and Linux. The framework employs Chromium for UI rendering and harnesses the power of Node.js in the backend to facilitate seamless integration with other libraries. An advantage of Electron is its flexibility in allowing developers to utilize their preferred front-end libraries to construct the UI of desktop apps. It supports an array of front-end technologies, including HTML, CSS, JavaScript, TypeScript, React, Bootstrap, Angular, Webpack, and many others. Furthermore, Electron provides an array of functionalities that streamline the desktop app development process efficiently. Its credibility is well-established, as it finds application in renowned companies for building their products, such as Slack, Microsoft Teams, VS Code, WordPress desktop, and Twitch, among others.

## Prerequisites
Before delving into this tutorial, it's essential to familiarize yourself with a set of technologies, which includes:
- JavaScript - A basic understanding of JavaScript is necessary since this language will be utilized for building your desktop app.
- Node.js and npm - Having Node.js and npm installed on your computer is crucial, as they are required for Electron and its library installations. Additionally, you should be acquainted with common operations in Node.js, such as require(), callback functions, events, and modules. If you don't have Node.js installed, you can get it from the official [Node.js](https://nodejs.org/en/download) website.
- Git and GitHub - While not mandatory, Git and GitHub are invaluable tools for code management and version tracking. They enable collaboration and code sharing with others. You can read more about [Git](https://git-scm.com/docs/gittutorial) and [GitHub](https://docs.github.com/en/get-started/quickstart/hello-world) from their respective websites.
- Front-end libraries - Proficiency in using HTML, CSS, JavaScript, and other front-end libraries is necessary for crafting your desktop user interfaces.
- Knowledge of desktop software terminologies - Understanding common desktop terms like menu bar, tray, window, icon, title bar, and taskbar is crucial. You can find resources to learn some of these terminologies at this website: [https://courses.lumenlearning.com/wm-compapp/chapter/terminology/](https://courses.lumenlearning.com/wm-compapp/chapter/terminology/).

## Setting up your project
First, create a folder in your directory(`electron-project`). Next, you’ll use your CLI to navigate to your newly created folder and initialize your project as an npm package. Without this, you won’t be able to install Electron.
``` 
cd electron-project
npm init -y
```
After this is done, you’ll use the command below to install the electron library:
```
npm install –save-dev electron
```
Once installed, you’ll go to your package.json file and change the `entry-point` field to `main.js`. Also, you’ll add a `start` command with a value of `electron` within your script field. In the end, your package.json file will look like this:
```
{
 "name": "electron-project",
 "version": "1.0.0",
 "description": "",
 "main": "main.js",
 "scripts": {
   "test": "echo \"Error: no test specified\"&& exit 1",
   "start": "electron ."
 },
 "author": "",
 "license": "ISC",
 "devDependencies": {
   "electron": "^25.3.2"
 }
}
```
Once the `main.js` file has been created, you can run Electron with the command below:
```
npm start
```
Although this won’t do anything because there isn’t any code in the `main.js` script, if it doesn’t return any error, it means you’ve properly installed Electron.

## Creating a browser window

In desktop apps, a browser window is a GUI(Graphical User Interface) that displays the content of an application. Every desktop app has Windows because, with it, the user can’t interact with their software. A typical window comprises a title bar, a close, minimize, and maximize button, and the application content.

In electron, Each window is made from HTML files. The files can be stored locally or from a URL.

To create a browser window in Electron, we’ll be using two modules: [`app`](https://www.electronjs.org/docs/latest/api/app) and [`BrowserWindow`](https://www.electronjs.org/docs/latest/api/browser-window). The `app` module is responsible for controlling the application life cycle of your application, while the `BrowserWindow` module is used for creating and managing the application windows.

Before writing any code in your main.js file, create an index.html file in the root folder of your project and add some code to it:
```html 
<!DOCTYPE HTML>
<html>
 <head>
   <title>Electron Demo</title>
   <meta charset='utf-8'>
 </head>
 <body>
   <h1>Welcome to Electron</h1>
 </body>
</html>
``` 
Also, add the code below to your `main.js` file.
```javascript
const {app, BrowserWindow} = require('electron');

app.whenReady().then( () => {
 let window = new BrowserWindow({width: 800, height: 600})

 window.loadFile('index.html')
}}
```
When you run `npm start` on your CLI, This will be the result:

![-](https://blog.openreplay.com/images/building-desktop-apps-with-electron/images/image01.png)

## Main process
All Electron modules are divided into two processes. They include the Main process and renderer process. In this section, I’ll be explaining what the main process is and the functionality its modules have.

The main process runs a Node.js instance and can access Node.js modules and any package on npm. Also, people call it the backend of desktop development because it comprises Electron modules that have access to the operating system's native API.

The `app` and `BrowserWindow` modules in our example above are also part of the main process.  

Here’s a description of some of the common modules in the Main process:

- [`app`](https://www.electronjs.org/docs/latest/api/browser-window) module - The app module controls the application event lifecycle. It contains methods that listen to different events in the application. It also has methods that allow you to get and set information about the application.

- [`BrowserWindow`](https://www.electronjs.org/docs/latest/api/browser-window) module controls and manages the browser windows. It includes functionalities that allow you to listen to events affecting the browser window and control it.

- [`process`]( https://www.electronjs.org/docs/latest/api/process) module: Originally, the processing module belonged to Node.js. But Electron has also added additional functionalities to it. Within this module, you can get information and control over the Electron and Node process.

In subsequent sections, we’ll be looking at the code examples of some of these modules.

## Renderer process
The Renderer process is the other process used in Electron. It acts as the front end of desktop development. Without it, you won't be able to use HTML, CSS, JavaScript, and any of your favorite front-end libraries to design the user interface of your desktop app. Unlike the main process, the Renderer process doesn’t have access to Node.js modules and native functionalities for security reasons. It only renders the web page and allows you to use any front-end library and web APIs you like.

In addition to using any front-end developer tools you like, the Renderer process also has access to its modules. A popular example is the webFrame module.

[`webFrame`](https://www.electronjs.org/docs/latest/api/web-frame) module is used for customizing the current web application. It contains methods that perform different functions, including controlling, customizing the zoom level, and inserting CSS into the web page.

In subsequent sections, we’ll be looking at the code examples of some of these modules.

## Interprocess communication

Due to security reasons, using the Renderer and Main process to communicate with each other is impossible. For example, when the app module is available for use in the renderer process, it is susceptible to hacking. Also, Renderer process modules like webFrame can’t be used in the main process. To solve this problem, Electron uses preload script and a set of modules for solving this problem. With these modules, you can access a limited set of functionality from the Renderer process. They include [ContextBridge](https://www.electronjs.org/docs/latest/api/context-bridge), [ipcMain](https://www.electronjs.org/docs/latest/api/ipc-main), and [ipcRenderer](https://www.electronjs.org/docs/latest/api/ipc-renderer).

- The `ContextBridge` module – has an [`exposeInMainWorld()`](https://www.electronjs.org/docs/latest/api/context-bridge/#contextbridgeexposeinmainworldapikey-api) method that allows you to safely pass a message from the renderer process to the main process. It’s a module in the renderer process.
- `ipcMain` module: This module in the main process handles the messages you send from a renderer process. Its method includes [`ipcMain.handle()`]( https://www.electronjs.org/docs/latest/api/ipc-main/ipcmainhandlechannel-listener)and so on.

   - `ipcMain.handle()` – this method sends a response for every call made by the renderer through the [`ipcRenderer.invoke()`](https://www.electronjs.org/docs/latest/api/ipc-renderer/ipcrendererinvokechannel-args) method.

- `ipcRenderer` module- This is a module in the renderer process that contains methods that send and listen to messages from the Main process. Its method includes the `ipcRenderer.invoke()` method.

   - `ipcRenderer.invoke()` – This method sends a message to the main process through a channel and expects results asynchronously. After the main process listens for it through the `ipcMain.handle()` method, it returns a promise that resolves when a response comes from the main process


<CTA_Middle_Frameworks />



## Creating trays and menu

One of the distinctive features of a desktop app is the presence of a menu bar and system trays. The menu bar is a navigation mechanism that gives you access to all the features in an app. It's always placed at the top of the screen. System trays provide access to some of the commonly used functions in your app. It's an icon placed outside your software on the right side of the taskbar (in Windows). You can easily add menus and trays to your project with a library like Electron.

Here's the code to add trays to your desktop app:
```javascript
const {app, BrowserWindow, Menu, MenuItem, Tray} = require("electron");

const trayTemplate = [
 {role: "undo"},
 {role: "cut"},
 {role: "copy"}
]

app.whenReady().then( () => {
 let tray = new Tray("tlogo.png");
   
 let contextMenu = Menu.buildFromTemplate(trayTemplate);
   
 tray.setToolTip("Tray Options");
 tray.setContextMenu(contextMenu);
      
 let window = new BrowserWindow({width: 800, height: 600})
      
 window.loadFile("index.html");
})
```
The result will be an icon on the right side of the taskbar:
![-](https://blog.openreplay.com/images/building-desktop-apps-with-electron/images/image02.png)

Here’s the code to add a menu to your desktop app:
```javascript
const {app, BrowserWindow, Menu, MenuItem} = require('electron');

const template = [
 {
   label: "Edit",
   submenu: [{ role: "undo" }, { role: "redo" }, { role: "forceReload" }],
 },
 {
   label: "View",
   submenu: [{ role: "reload" }, { role: "zoomIn" }, { role: "zoomOut" }],
 },
];

app.whenReady().then(() => {
 const menu = Menu.buildFromTemplate(template);

 Menu.setApplicationMenu(menu);

 let window = new BrowserWindow({ width: 1000, height: 800 });

 window.loadFile("index.html");
});
```
Result:
![-](https://blog.openreplay.com/images/building-desktop-apps-with-electron/images/image03.png)

## Modules in the Main process
In the preceding sections, I explained some of the main process's modules and their main function. In this section, we’ll look at some code implementation of these modules.

### app module 
The app module controls the application event lifecycle. Some of the methods in the app module are:

- [`app.on()`](https://www.electronjs.org/docs/latest/api/app/#events) - This method is called when certain events are emitted. Some events are: `window-all-closed`, `browser-window-created`, and so on.
```javascript
//this will execute when all the windows are closed
app.on("window-all-closed", function () {
 console.log("all windows closed");
});

//is emitted when a new BrowserWindow is created
app.on("browser-window-created", function () {
 console.log("browser window created");
});
```
- [`app.quit()`](https://www.electronjs.org/docs/latest/api/app/#appquit) – This method tries to close all windows
```javascript
app.whenReady().then( () => {
 app.quit() 
})
```
- [`app.whenReady()`](https://www.electronjs.org/docs/latest/api/app/#appwhenready) – is a promise function that is fulfilled when Electron is initialized.
```javascript
app.whenReady().then( () => { 
 //Quits the app
 app.quit() 
})
```
- [`app.getVersion()`]( https://www.electronjs.org/docs/latest/api/app/#appgetversion)– returns the version of your app as found in your package.json file.
```javascript
app.whenReady().then( () => { 
 //returns the value of your app version
 app.getVersion() 
}) 
```
- [`app.getName()`]( https://www.electronjs.org/docs/latest/api/app/#appgetname)– returns the current application name as found in the package.json.
```javascript
app.whenReady().then( () => {
 //returns the name of your application
 app.getName() 
}) 
```
- [`app.getLocale()`](https://www.electronjs.org/docs/latest/api/app/#appgetlocale) – returns the current application locale. Its value can be `en-US`, `en-IN`, and so on.
```javascript
app.whenReady().then( () => {
 //returns the current application locale
 app.getLocale () 
}) 
```
### BrowserWindow module 
This module controls and manages the browser windows. Here are the functionalities:

- [`new Browserwindow([options])`](https://www.electronjs.org/docs/latest/api/browser-window/#new-browserwindowoptions) – This creates a new browser window with an options argument that sets the Windows native properties. Some of its properties include `height`(specifies the height of the window), `width`(specifies the width of the window), center(whether the window should be in the center of the screen), `x` and `y` (specifies the left and top offset), `movable`(specifies whether the window is movable or not), `closable`(specifies whether the window is closable or not), `fullscreenable` (whether the window can be put into fullscreen mode).
```javascript
app.whenReady().then( () => {
 //creates a browser window with a defined size
 let window = new BrowserWindow({width: 800, height: 600})

 //attaches a web page to the browser window
 window.loadFile("index.html")
})
```
- [`window.on()`]( https://www.electronjs.org/docs/latest/api/browser-window/#instance-events)method: This method is called when certain events are emitted by the browser window. Some of them are `minimize`, `maximize`, and `move`.
```javascript 
app.whenReady().then(() => {
 //emitted when the window is minimized
 window.on("minimize", function () {
   console.log("Browser window minimized");
 });

 //emitted when the window is maximized
 window.on("maximize", function () {
   console.log("Browser window maximized");
 });

 //emitted when the window is moved to a new position
 window.on("move", function () {
   console.log("Browser window moved");
 });
});
```
- [`window.fullScreen`]( https://www.electronjs.org/docs/latest/api/browser-window/#winfullscreen)– is a Boolean property that returns true if the windows are in fullscreen mode
- [`window.minimizable`](https://www.electronjs.org/docs/latest/api/browser-window#winminimizable-macos-windows) – is a Boolean property that returns true if the window can be manually minimized by the user
- [`window.maximize()`](https://www.electronjs.org/docs/latest/api/browser-window/#winmaximize) – maximizes the window
- [`window.getBounds()`](https://www.electronjs.org/docs/latest/api/browser-window/wingetbounds)– returns an object containing the x, y, width, and height of the windows
- [`window.center()`](https://www.electronjs.org/docs/latest/api/browser-window/#wincenter) – moves windows to the center of the screen

### Process module 
Originally, the process module belongs to Node.js. But Electron has also added additional functionalities to it. Some of them include:

- [`process.type`](https://www.electronjs.org/docs/latest/api/process/#processtypereadonly) – returns a string representing the current process type. Its value can be `browser`, `renderer`, `worker`, or `utility`.
- [`process.versions.chrome`](https://www.electronjs.org/docs/latest/api/process/#processversionschromereadonly) – returns a string representing Google Chrome’s version string
- [`process.versions.electron`](https://www.electronjs.org/docs/latest/api/process/#processversionselectronreadonlu) – returns Electron’s version in a string
- [`process.getSystemVersion()`](https://www.electronjs.org/docs/latest/api/process/#processgetsystemversion) – returns the version of the host operating system.

## Modules in the Renderer process
In addition to being able to use your front-end libraries and web APIs, the renderer process also has multiple modules of its own. A popular one is the webFrame module.

webFrame module – This module is used for customizing the current web page. It contains methods that include:

- [`webFrame.setZoomFactor()`](https://www.electronjs.org/docs/latest/api/web-frame/#webframesetzoomfactorfactor) – This method sets the zoom percent of a webpage. 2 means 200%.
```javascript
const {webFrame} = require("electron");

webFrame.setZoomFactor(3)
```
- [`webFrame.setZoomLevel()`](https://www.electronjs.org/docs/latest/api/web-frame/#webframesetzoomlevellevel) – zooms the webpage 20% larger or smaller. A default of 0 means 100%.
```javascript
const {webFrame} = require("electron");

webFrame.setZoomLevel(2)
```
## Packaging your Electron app
After writing all the code logic for the desktop app and spending hundreds of hours optimizing your work, the final thing to do is packaging. 
TO package your electron app, you’ll need to install another library called `electron-forge`. [Electron forge](https://electronforge.io) is a library that allows you to build and publish your app for use on various platforms.

To package your app, here are the things you need to do:

First, install the electron-forge CLI library:
```
npm install –save-dev @electron-forge/cli
```
Next, you’ll import your existing electron project with the script below:
```
npx electron-forge import
```
Finally, you run this command to create a distributable for your configured maker and platform.
```
npm run make
```
When the script finishes running, a newly created `out` folder will be in your project. It’ll contain both the distributable and your packaged application code. Your distributable will be in the out/make folder. Check the [electron-forge website](https://www.electronforge.io/config/makers) for more information on how to configure for different makers and add icons for your app.

## Performance and security considerations
To keep your electron app  performant, here are some of the things you need to do:

- Before adding a Node.js library to your app, always check the size of its dependencies(the smaller, the better) and the time it takes to perform the function you need(the faster, the better)
- Avoid making unnecessary network requirements. If there are resources(images, font, and so on) your app needs, it’s better to include them in your app’s bundle.
- Don’t block the main process. If you have any CPU-intensive task, you should make use of worker threads.
- Don’t immediately run all your code when your application starts. Instead, consider a strategy that executes your code at the right time.

To keep your app secure, here are some of the things you need to do:

- Don’t install 3rd-party libraries with known vulnerabilities
- Always perform security testing and adopt secure software development practices when building
- Use local files (not remote code ) to execute your Node.js code because your app might be vulnerable to cross-site scripting (XSS).
- Always use a current version of Electron and Node.js.

## Conclusion
Throughout this tutorial, among the numerous things explained, we’ve learned how to install and package Electron. We’ve also learned about the capabilities of the Main and Renderer process. We’ve also learned how to keep your app secure. I hope you found this article useful. You can visit the official [Electron documentation](https://www.electronjs.org/docs/latest/) to learn more.