Using Web Technologies to create your first Cross-Platform Desktop Application with Electron
Having build Websites during all my years of experience, I have to admit, creating a piece of software that runs on a Desktop Environment sounded tedious to me as I always thought I had to learn about a whole new toolset.
But when I came across Electron, I realized that Desktop App development isn’t as intimidating as It once was.
What is Electron? How can a subatomic particle help me develop Softwares?
First of all, when I say Electron, I am referring to the Open Source Software Framework that allows for the development of desktop GUI applications using web technologies like HTML, CSS, JavaScript, etc.
Why Electron?
Cross-Platform
There are many tools out there that can help you develop Softwares that run on different Operating Systems but only a few are capable of providing cross-platform compatibility. Thankfully, Electron does, which is one of the main reasons It became so popular, along with allowing Web Developers to use their Website Building Experience for Software Development.
Reusability
Since we are using web technologies, the same source code for the UI can be deployed as a well-functioning Website on any service you like. So we are giving importance to the principle Code Once, Use Everywhere.
Security
From large-scale web-based Softwares like Microsoft Teams to Code Editors like Visual Studio Code and Atom are developed in Electron. If that’s not a testament to the level of Security Electron provides, I don’t know what is.
Performance
If proper care is taken while developing (load only what you need), Electron can show some great gains in the terms of performance when compared to native applications.
Cost and Time
We are using our experience as Web Developers to develop Desktop Apps, which saves us time to learn about various desktop application development Tools and start from scratch, and also helps us skip over different Native Features of different Platforms.
Electron’s Architecture? A Blackbox?
Let’s see how Electron works.
- When you launch an electron application, a request is made to open the window Object(the one you see in the front-end) by the main process.
- The Window Object or commonly known as the Renderer process when ready/programmatically defined, loads up.
No Desktop Application is complete without Native Features so here’s how it would work in an Electron App.
- An event is raised by the renderer process in the front end.
- The Renderer process emits the event to the main process(coded in NodeJS).
- The Main Process constantly listens for various events, in this case, let’s assume we have coded the event to write a file to the local file system.
- The Main process upon receiving the event, acts on it by accessing the Native APIs which in our example, will write to the computer file system.
Popular Software built with Electron
- Visual Studio Code (VS Code)
- Slack
- Tusk
- Mailspring
- Skype
- Discord (My Personal Favorite due to the wide array of features)
- WhatsApp Desktop
- Atom
How do we do it?
Now that I have gone over the basics of how Electron works and why you should spend time mastering it.
Now we must use those basics to actually develop something that we can use. That means We start coding now.
Prerequisites
- NodeJS
- Code Editor // I use VS Code
- Some Experience in NodeJS and Front-End Development
- A Happy and Fresh Mind
Getting Started
I am assuming you have fulfilled all the prerequisites of the tutorial, especially the last one along with NodeJS and your Code Editor installations.
You can verify NodeJS installation by typing the following commands in your terminal
node -v
npm -v
If the above commands do not print out the version of NodeJS and NPM, you need to go through their official documentation and install it before you go any further.
So now we need to visit Electron’s Official Website for some basic information like how to set up electron locally. But It is optional as I will be going over it step by step.
Create the Project
You need to create a directory in your computer that will hold the source code of the project, I will only be using terminals for such tasks so You can perform the following command to create the directory and move in it
mkdir electron-demo
cd electron-demo
Where is Electron?
Before you install Electron, you need to initialize the project with the following command.
npm init -y
The above command will create a basic package.json
file in your root directory. We will be using that file to create scripts and install npm packages in our project as we progress further into this tutorial.
Now we need to install Electron into the project by typing the following command into the terminal
npm i --save-dev electron
This command will generate the folder called node_modules
and a package-lock.json
in your project root directory. You can verify the installation of Electron by going into node_modules
and looking for electron
directory.
The --save-dev
flag installs Electron as a dev dependency. Why we did that? Because when We package an application, Electron is no longer required for it to run.
Coding the Application
Configuring main.js
main.js
is the file which that serves as the entry point to our Electron Application. But main.js
is just a name, and also the convention because It will run the Main Process which controls the lifecycle of the application and accesses Native APIs.
You can name it whatever you want, only thing is to specify the main
file in package.json
But remember, there can only be one main file.
So, let’s create a main.js
in your project root, and put the following code into it.
Now, Let’s go over what is there in the code.
- line 1: we are importing
app
andBrowserWindow
from Electron package.app
is the module which controls the application’s event lifecycle andBrowserWindow
creates and manages the Windows we see in UI. Individually you can go toapp
andBrowserWindow
documentation to explore them and their events. - line 5: we are creating a BrowserWindow with the options we have given. Leaving the ones which are self-explanatory, let’s go over
nodeIntegration
andenableRemoteModule
.
1. nodeIntegration: Allows the BrowserWindow to access NodeJS API.
2. enableRemoteModule: Enables the BrowserWindow to access
the remote module which to summarize helps establish communication between the main process and the renderer process. - line 16: We are loading the
index.html
file inside the window. We will create that file next. - line 18: We are telling the window to quit
app
when the window itself closes. - line 23: We are telling
app
to create the window when it finishes loading. - line 25: We are adding a new listener that tries to quit the application when it no longer has any open windows. This is not required in macOS, so the
if
statement. - line 31: We are adding a new listener that creates a new browser window only if when the application has no visible windows after being activated. For example, after launching the application for the first time, or re-launching the already running application.
Creating index.html
Now we need to create the file which we will be seeing in the BrowserWindow. In our case, It is index.html
as defined in Line 16 when we created main.js
.
In the Code above, Let’s focus on how we are printing the RAM and also the version of Chrome on which the browser window is running.
The script tag is printing the information with the process module, which is only available to the BrowserWindow Object because we enabled nodeIntegration
while writing main.js
above.
Now that we have the back-end and front-end set up, How do we see the result?
- For that, we need to add a script in
package.json
. So open it and inside thescripts
add a new entry"start" : "electron ."
- We also need to point to our entry point NodeJS file, which in our project is
main.js
. So we modify"main": "main.js"
.
So package.json
will start looking like below.
Now, all we need to do is run the script, which we can do by going into the terminal, navigating to the root directory, and typing the following command.
npm start
If everything is correct, We should see the following screen pop up.
Helpful Tip — We have programmed our main process to load the file called index.html
but We could also have a pre-existing website load directly into the Window by window.loadURL('https://google.com')
instead of window.loadFile('index.html')
in main.js
. So we don’t need to write extensive code to port our websites into a Desktop Application. Electron got you covered.
But for the sake of experimenting, We will keep it at window.loadFile('index.html')
.
Inter-Process Communication
It is not a desktop application if it doesn’t interact with the native APIs.
So we will perform a basic operation to showcase Electron’s ability in that regard.
We can do that with IPC (Inter-Process Communication) modules.
The main process and the renderer processes use ipcMain
and ipcRenderer
modules respectively.
The flow we will follow goes as:
- An Event occurs in BrowserWindow which emits a signal along with optional data to the main process.
- The Main process in response to the event signal, may return some data back to the renderer process(BrowserWindow) or perform operations in the back-end or both.
NOTE — This is possible because we enabled Remote Module in main.js
when we were creating the BrowserWindow.
Let’s see this in action.
In the code above, let’s focus on the content inside <script>..</script>
tag.
- We are loading in the ipcRenderer module from the electron package, which is only available to us because we have enabled
remoteModule
inmain.js
. - We are adding an
click
event listener to a button in the HTML which will emit a signal calledperformActions
for the main process to listen. - We are also sending an object that contains the two input fields of
firstName
andlastName
as an argument upon which the main process will perform desired actions.
Now, where is the event being handled? We do that in main.js
.
Understand the new code? Well, Let me explain it to you anyway.
- The first difference compared to previous
main.js
is that now we are importing 2 additional packages, known asipcMain
anddialog
. ipcMain
comes into action in line 36 when we add an event listener(performActions
) to it.- In my example of using native functionality, I am using the data I received from the form (
firstName
&lastName
), and creating a native dialog box that appears in the BrowserWindow.
NOTE— To Display a dialog is a User Choice, I wanted to keep the tutorial as simple and easy to understand as possible.
A Practical Example would be to use NodeJS’s fs
module to store the data somewhere on the local file system and send it to BrowserWindow
on the first launch or upon any other event.
How is a dialog different from a modal?
Well, a Modal is a custom CSS-made element that stays the same for all the platforms. But a dialog created by accessing the Native APIs will change depending on the Operating System.
There are too many Native Modules for me to go over so You can click here to explore them all in the official Documentations.
There are multiple types of dialog boxes in a System, you can explore them here.
This concludes the tutorial on Using Web Technologies to create your first Cross-Platform Desktop Application with Electron
You can also visit the Github Repository for this project to view the complete Source Code.
Alternatives to Electron?
Flutter
Pros
- Open Source
- Great Number of features like Debugging tools, Hot reload
- Based on Dart Language
Cons
- Still in Development
- Underwhelming Community Support compared to Java or Kotlin
B4X
Pros
- Great Community
- Easy and Fast
- Live Code Swapping // Hot Reload
- Very Powerful for IoT // Support for Bluetooth/BLE, MQTT, TCP/UDP, Serial, NFC, Websockets, HTTP/2 across platforms makes it the ideal tool for IoT projects
Cons
- Java Dependent Desktop Environment
wxWidgets
Pros
- Mature
- Truly Native Look and Feel
- Open Source
Cons
- Heavy Compiled Result
Proton Native
Pros
- Very Fast
- React Style
- Fully Cross-Platform Compatible
- Lightweight
- Code reusable with React Native Apps
- Native Components
Cons
- Community Support I found to be very dry compared to Electron.
- The number of Components is very less at this moment.
Other Tools
- JavaFx
- NodeGUI
- React Desktop
- Swing
What’s next?
Now we can explore the documentation to experience the full toolset.
Since NodeJS is the language service for the main process, you can combine it with Front End Technologies like React, Angular to create comprehensive Full Stack Desktop Applications that give you the look and feel of a Modern-Day Customized Application along with a reliable and function-rich Native Environment by fully utilizing the potential of NodeJS and the NPM Library.
You can also learn to package your application and making it available publically for everybody to use by visiting the official documentation on distribution.
If You liked this article, please show appreciation by either Clapping or commenting or both. More to come.
You can also go to my Github Profile and view my work, or visit my LinkedIn and connect with me personally if you have any doubts or feedback regarding this article or anything else.
Happy Coding…