Want to build Desktop apps using JS? Say hello to Electron

What is Electron?

I think it’s safe to say Javascript is used everywhere at this point. From NodeJS for the backend, React and Vue for the frontend, and Cypress and Jest for testing, it can handle a lot. But what if we want to build an actual application to be used on our computers? Welcome Electron. With Electron, all we need is HTML, CSS, and Javascript. You can use whatever library or framework you like by simply installing it into your codebase. Some big name applications have been built with it, and I have attached a few of the more notable ones:

  • Slack – A messaging app for teams
  • Atom – A hackable text editor for the 21st century
  • Visual Studio Code – Open source code editor built by Microsoft
  • WordPress – A desktop app for WordPress

If you would like to see a more robust list of applications built with Electron, I have attached the link here https://www.electronjs.org/apps.

Building the application

All we need to get started is a terminal and a code editor. I like to use my Macs built in terminal, and I used visual studio code for development. There are plenty of options, and most code editors have some form of built in terminal, so use whatever you are comfortable with. We will also need to have NodeJS & NPM installed on our computers. The official docs recommend you having the latest stable release installed, which is v14.16.1. To check on this, we can open our terminal and run the following command:

node -v

If you have the latest version, great. If not, simply update your version of Node by running the following command:

npm install -g n stable

What this will do is install the latest stable version of node globally. Once this is complete, we will setup a basic Electron application. At the most basic level, an Electron application is a NodeJS application. This essentially means our starting point is a Package.json, like anything else that was built with NodeJS. To build our app, we will want to run a few basic commands in terminal. First, make sure you are in the directory where you want your app to live. Then you will want to run the following commands:

mkdir my-electron-app && cd my-electron-app
npm init -y
npm i --save-dev electron

What this did was created our folder, and called it my-electron-app, and then we moved into that folder. Next we initialized a very basic Package.json file(We will edit this in our code editor). Lastly we installed electron into our project, and added the dependency to our package.json file. If all went well, it should look like the following:

As you can see, we have a file with a single entry in devDependencies. This allows us to start working with Electron at a basic level. There is only a single file we need to create to build our application. . Let’s call it index.js. Once we have this file created, we can start building our application. For this article, we will build an application that displays the discord web app, so we can run it from our machine without having to go into our browser every time. Lets build our index.js file out.

First, we will need to import 2 things from Electron, which are app and BrowserWindow. We will accomplish this by requiring the following:

const { app, BrowserWindow } = require("electron");

This allows us to use only what we need, and we ignore what we don’t need.

Next, we will want to set up the applications initial size. Since I use a 13″ laptop, I gave it a somewhat small initial size. It has an initial width of 1000px, and a height of 800px; The benefit of keeping it initially small is it will look nice on almost any laptop or desktop screen. To do this, we will want to add the following lines of code:

let applicationWindow;
const browserWidth = 1000;
const browserHeight = 800;

function createWindow() {
  applicationWindow = new BrowserWindow({
        width: browserWidth,
        height: browserHeight
    });

    applicationWindow.loadURL("https://www.discord.com");
    applicationWindow.on("closed", () => { 
      applicationWindow = null; 
    });
};

A few different things have happened here. Let’s walk through this together.
First, we create a variable named applicationWindow, and we leave this with no value assigned. We then create 2 variables for the browserWidth and browserHeight, and we assign those values. Next, we create a function named createWindow(). Inside that, we assign our original variable applicationWindow with a new instance of the imported BrowserWindow, which is what we imported originally. Inside that new instance of BrowserWindow, we are giving it a height and width using the 2 variables we created.

Since our application is now rendered, we are half way there. The other thing was want is for our app to load a URL into the application directly. For this, we can use the loadURL, which is built into Electron. I have attached the snippet of code from the library directly. We can pass in a url, some options, and it returns a promise.

/** You can load a URL using a `POST` request with URL-encoded data by doing the
* following:
*/

loadURL(url: string, options?: LoadURLOptions): Promise<void>;

For our use case, we will simply pass in https://www.discord.com, and that is what our application will load. Now that we have created our application at the size we care about, we want to write some functionality to call the function we created at the points we care about. We also want the application to stop when we close the window. These 2 things can be handled by the following:

// This will call the createWindow() when we start the application
app.on("ready", () => { 
    createWindow(); 
});

// This will quit the application if the windows are closed.
app.on("window-all-closed", function() {
  if (process.platform !== "darwin") app.quit();
});

app.on("activate", function() {
  if (applicationWindow === null) createWindow();
});

At this point, our application is complete. We have defined the size of our app, what we want to load, and when we want to load it. We also have logic to quit the application once the window is closed. The full applications code is below:

const { app, BrowserWindow } = require("electron");

let applicationWindow;
const browserWidth = 1000;
const browserHeight = 800;
function createWindow() {
  applicationWindow = new BrowserWindow({
        width: browserWidth,
        height: browserHeight
    });

    applicationWindow.loadURL("https://www.discord.com");
    applicationWindow.on("closed", () => { 
      applicationWindow = null; 
    });
};

app.on("ready", () => { 
    createWindow(); 
});

app.on("window-all-closed", function() {
  if (process.platform !== "darwin") app.quit();
});

app.on("activate", function() {
  if (applicationWindow === null) createWindow();
});

We need to do one final thing in order to run our application. In our package.json file, we need to add a line to our scripts, and that is the following:

"start": "electron ."

Once this has been added, head over to terminal and run the following command:

npm run start

What did we just build?

If everything works as expected, you should see the following, which is exactly what we want!

Final thoughts

While this is a very basic example of what you are able to do, the sky is the limit with Electron. You have access to chrome developer tools inside your application window, so you can debug like you would. You can also check on network calls, and inspect your Elements all from a single place. As a frontend software engineer, being able to build a full fledged desktop application with the same tools I use in my day-to-day job is very exciting to me.

Below are two helpful resources that I followed when writing this post:

https://www.electronjs.org/docs/tutorial – A tutorial from the official docs
https://www.youtube.com/watch?v=kN1Czs0m1SU – Traversy Medias guide on how to build a full Electron app

As always, if you see something you like, or something I can improve upon, leave me a comment below. I hope this has been helpful, and happy coding!

The Author: Jeremy Grice. If you’d like to follow me, here are my Twitter and GitHub accounts.

Leave a Reply