An introduction to the Electron framework
This article is part of a series of blog posts aiming to deep dive into the Electron framework for creating cross-platform desktop applications with web technologies.
In this post, we’ll look at the basics of Electron, including what it is, how to use it, and some advantages and disadvantages of the framework.
Disclaimer: To get the most out of this series, it’ll be helpful to have at least some prior experience with core web technologies like HTML, CSS, Javascript, NodeJS, and frontend frameworks like React or Vue.
What is Electron?
Electron is a framework for developing cross-platform desktop applications, embedding NodeJS and Chromium in a single platform to provide an easy-to-develop experience.
As a developer, you can use all of your knowledge of web technologies to quickly create desktop applications with Electron, without the need to use specialized or proprietary technologies specific to each operating system.
Electron also provides the added benefit of having a cross-platform codebase, which greatly simplifies the process of deploying your application to different operating systems.
The Electron framework is more widely used than you might think. Many of the high-profile applications that you use day-to-day could be implemented using Electron, including:
- Slack
- VSCode
- Discord
- Figma
- Microsoft Teams
Using Electron
When we think of running a traditional single-page web application, we can probably assume that it’s going to be executed in a browser environment. In a similar vein, when we think about desktop applications, we know that they’re going to be running as their own separate processes that are handled by the operating system.
Running an Electron application
An Electron application runs two separate processes in tandem:
- The main process has access to the Operating System through NodeJS APIs and controls the lifecycle of the Electron application.
- The renderer process runs in a sandboxed Chromium environment and has the sole responsibility of showing the user interface.
Both of these processes can communicate with each other using IPC (Inter-Process Communication) channels to send and receive information. These communication channels are implemented similarly to event handlers that act upon receiving messages from the other process.
A simplified diagram of the general infrastructure of an Electron Application. The main process uses NodeJS and the renderer process can use frontend frameworks like Vue, React, Svelte, and others.
Main process
The main process acts as the application’s entry point and runs in a NodeJS environment. This means we can use all of the NodeJS APIs in our application and do things like write files in the filesystem or extract information from the operating system with the ‘fs’ or ‘os’ NodeJS APIs respectively.
The application’s lifecycle is also controlled in the main process. This is done in Electron by creating event handler functions for different application lifecycle events.
A common example of this is initializing the renderer process after the Electron framework is done initializing. To accomplish this, we would need to subscribe to the ‘ready’ event of the Electron application and execute the code to load the renderer process when this event occurs.
In a similar way, we can use these events to execute code before the application is closed or other actions are executed.
Renderer process
The renderer process is kickstarted by the main process and consists of a Chromium-based environment that executes the provided HTML entry point code like a browser. Think of the renderer process as an embedded browser instance that runs a specific web page or application that’s specified from the main process. Additionally, you can enable specific Electron APIs to be used by the renderer process through the usage of a preload script–a crucial step to ensuring that both main and renderer processes can talk through IPC channels.
The usual use case would be creating one renderer process that executes a single page application and works as the front end of the entire Electron application. However, it is possible for Electron to spawn multiple instances of renderer processes that could point to different entry point webpages. This can be useful in separating one big application into multiple smaller chunks that are loaded when a specific application window is needed.
Since we’re essentially running a browser pointing to a web page, we can run web applications created with frontend frameworks (like React or Vue) in the renderer process, with the caveat that we will need to communicate with the main process using the IPC mechanism.
Inter-process communication
As the name suggests, the way in which both main and renderer processes communicate with each other is by using IPC channels.
Traditionally, when we work with web applications, it’s expected that we talk to a backend service using query request APIs, which are most likely executed through HTTP and respond with data in a structured manner.
But this is not entirely true for the renderer processes of Electron applications. Because these are executed in a sandboxed browser-like environment, it’s highly likely that we will need to ask the main Electron process (using IPC channels) for data instead of fetching it from an external service directly from our frontend application.
IPC channels are defined by a unique string identifier, which can be used in both processes to either listen to or send messages through the channel.
In the main process, we directly define the function handlers for each IPC channel. Whatever value we return from the handler will be used as the response message sent to the renderer process that called it. We can also call a channel directly to send data to the renderer process at any time.
Meanwhile, in the renderer process, IPC channels are defined in the preload script provided by the main process. Messages can be sent or received by using the Electron APIs exposed to send and receive messages.
Note that only the channels and APIs exposed in the preload script will be available in the renderer process.
Advantages and disadvantages of Electron
Taking an Electron application infrastructure into consideration, we can get a lot of benefits from having the mature ecosystem of NodeJS and battle-tested frontend frameworks that we can choose from to develop our application.
Here’s a list of some of the main advantages of using Electron:
- A wide array of NodeJS libraries and extensions can be used to extend the main process functionality.
- Frontend frameworks can be used to easily develop the graphical user interface of our desktop applications. This includes frameworks like TailwindCSS for styling or Jest for unit testing.
- Web developers can quickly learn to work with Electron since it uses the same core technologies that they’re used to.
- Electron has available plugins for cross-platform builds and over-the-air updates that work with most Electron application configurations.
However, we also need to take into account that we will basically be bundling an entire Chromium-based browser with every application that we deliver, ballooning the size of our application from the start and carrying over any number of problems that come with having a browser as our graphical user interface and NodeJS as the driver of our main process.
Some other disadvantages of using Electron are:
- NodeJS has real performance drawbacks compared to native solutions that can run binaries directly compiled to the operating system.
- There is a limit to the number of Electron and NodeJS APIs available when developing, and in some cases, it might be necessary to write specialized wrappers for specific functionality required at the operating system level.
- In terms of security, you need to consider the attack surface of having an entire browser running on your application, and any attack vector that might affect a web page can affect an electron application in the same manner (even with the sandboxing strategies applied by the framework on renderer processes).
- If you don’t plan to distribute your application to multiple operating systems, it might be overkill to use a framework that is built for this purpose.
In conclusion
Electron is a very mature framework that web developers can use to quickly create desktop applications. It has a proven record of being used to develop high-profile applications, further highlighting its ease of use and development. However, it’s also important to consider that these advantages can also come with certain performance drawbacks and real security concerns.
In the next post of this series, we will deep dive into creating a simple Electron project that uses popular web development frameworks for its graphical user interface. We will learn how to write code using the architecture exposed in this article and get a working demo running successfully.
References
Electron main web page: https://www.electronjs.org/
Electron documentation: https://www.electronjs.org/docs/latest/