What is Electron

I think the description on the ElectronJS.org page says it best:

If you can build a website, you can build a desktop app. Electron is a framework for creating native applications with web technologies like JavaScript, HTML, and CSS. It takes care of the hard parts so you can focus on the core of your application.

Electron is designed so that almost any framework or library that you use to build a web site can be used to build a desktop application. These applications can run on Windows, MacOS, or Linux. Chances are you’re already using an application built using Electron. The Atom Editor, VS Code, and Slack are just a few of the many apps built using electron. Electron has a list of many of the apps. This list is by no means exhaustive, it’s only the ones that have added themselves to the list.

Tools and requirements

There is very little that is required to start working on an Electron app. And if you’ve been creating web sites, you most likely already have them installed. You’ll need an code editor of some sort, and you’ll need Node. NPM is also used, but it’s installed with Node so there isn’t anything to install.

Editor

Online wars have been fought about which editor is best. For Electron it doesn’t matter what code editor you are using. For me I’ll be using Visual Studio Code. It’s free, has a large amount of plug-ins and extensions. And constantly being updated with new features. VS Code is available on Windows, Mac and Linux. And well, it’s also using Electron.

Node & NPM

Node is a JavaScript Runtime that let’s you run JavaScript outside a browser. It can be used to run JavaScript directly on the desktop or it can be used as a Web Server. We’re not going to get too fancy with what Node can do, but we’ll need to get it installed for Electron. If you don’t have Node installed please go to NodeJS and follow the instructions for your operating system.

NPM will be installed along with Node. So what is NPM? This is a package manager. Using a package manager we can easily install any package with just a single command. The best part is that if the package we want has a dependency on other packages it’ll install them too. And it’ll do the same for those dependencies as well.

To verify that Node and NPM are installed properly, type the following two commands into a command prompt. They will give you the versions that you have installed. If they aren’t installed, please check the installation.

node -v
npm -v

Hello World App

Building a Hello World App is a great way of making sure all the items are installed and setup before spending a lot of time creating a complicated application. This app will be as basic as possible. We’re just going to get the app started.

Project Folder

Make a folder and open a command prompt to that folder. For me I’m calling it helloworld.

Initialize NPM

We’re going to create a package.json file. This file contains a lot of information about the what is being creating; including the packages that NPM. The -y puts the default answer into the questions that come up. These answers can be changed by editing the package.json file.

npm init -y

This is the package.json that was created for me. We’ll be doing some editing of this file later, and so will NPM when we have it install Electron.

{
  "name": "helloworld",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "Russ Eby",
  "license": "MIT"
}

Creating our files

We’ll need some files to use. Please create these files for us to edit.

  • index.js
  • index.html
  • main.js

Installing Electron

We’re going to use NPM to install electron for us. From inside the helloworld folder, I’ll run the following command. At the Electron on NPM page has information about using NPM to install Electron. Make sure that the package.json file is closed. If you leave it open while NPM is installing packages, the file file may get out of sync.

npm install electron --save-dev

Since this is our first time installing using NPM in this application, a folder called node_modules is created. Inside is Electron and all the dependices needed to run Electron. Opening this folder, you’ll see a lot of folders inside. Each is a dependency needed to run Electron. Do not edit, add, delete or move anything inside this folder. Always use NPM to make any changes of adding or removing packages.

main.js

This file is going to be our kick off file. It’s going to contain the code to get Electron up and running. Since we’re putting it in it’s own file, we can just use it for all of any future projects. We may need to make changes as our projects become more advanced.

These first three lines are bringing in code that we’ll be needing. The first is bringing in parts of Electron. The next two lines are bringing in parts of Node that will let us access the file system.

const { app, BrowserWindow } = require('electron');
const path = require('path');
const url = require('url');

Our window needs to be stored somewhere. This window will be where our app will be displayed.

let win;

We need a function that will let us create this window that we’re going to use.

function createWindow() {

We now will new up a BrowserWindow. Passing in an object with the width and height of the window. The nodeIntegration isn’t strictly required for apps you’ll be making. But it is required for something we’ll be doing in this app and it’s very common in Electron apps.

    win = new BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: { nodeIntegration: true }
    });

Using loadURL we’ll be loading the index.html file into the window.

    win.loadURL(url.format({
        pathname: path.join(__dirname, 'index.html'),
        protocol: 'file:',
        slashes: true
    }));

Here we tell win that on the closed event we want to set the win to null. This will make sure that when the application is closed that it’s removed from memory. Otherwise there is a chance of a memory leak.

    win.on('closed', () => {
        win = null;
    });

This next part is completely optional and most likely you will not want them in production code. This line will start the application with the dev tools opened.

    win.openDevTools();
}

These next three events are part of the Electron App.

On the ready event we want the app to run the createWindow function.

app.on('ready', createWindow);

On MacOS even after all windows are closed it doesn’t mean the app is exited. So we need to make an except for Darwin (which is the platform name for MacOS) so the user can use Cmd + Q to exit the application.

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

On the activate event we will createWindow if win is null.

app.on('activate', () => {
    if (win === null) {
        createWindow();
    }
});

Updating package.json

If you remember when we looked into the package.json file, there was a line "main": "index.js",.

In the package.json file, there is a line "main": "index.js", that tells Node and Electron what JavaScript to start with. In effect bootstrap the application. Right now it’s set to index.js. But we put all the loading JavaScript in the main.js file. Please edit the package.json file and change it to "main": "main.js",.

While were in here, let’s add an item under the scripts section. Electron’s command to start it is electron .. It’s very common and most people are expecting to have the start command for all apps using NPM is to be npm start. So let’s add a script that will make this happen.

Edit the scripts section to look like this.

  "scripts": {
    "start": "electron .",
    "test": "echo \"Error: no test specified\" && exit 1"
  },

With this addition, we can now run the app by using electron . or the more standard npm start.

The entire package.json file now looks like below.

{
  "name": "helloworld",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "Russ Eby",
  "license": "MIT",
  "devDependencies": {
    "electron": "^5.0.2"
  }
}

Also notice that a new item was added by NPM; devDependencies. These are dependencies that are only used during development. They are not meant to be part of the production app. For production items they’ll be listed under dependencies.

index.html

For the HTML, this is pretty much exactly the same as what you will see in a web site.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Hello World</title>
</head>

<body>
    <h1>This is the Hello World App</h1>
    Node Version
    <script>document.write(process.versions.node)</script>
    <div>
        <button id="close-button">Close App</button>
    </div>
    <script src="index.js"></script>
</body>

</html>

There are two lines that I need to point out.

In this line, we’re using the process from Node and we’ll display the version of node being used.

<script>document.write(process.versions.node)</script>

Even though we haven’t put anything in the index.js file, we’re going to add it to the bottom of the HTML file so the JavaScript we add will used. Even without anything in the index.js file, that application will still run. But let’s add some function to the button that is sitting there.

<script src="index.js"></script>

index.js

First thing we’ll need to do is load electron so we access the window itself.

const electron = require('electron');
const remote = electron.remote;

Using just a standard getElementById we’ll be adding an event listener that will grab the current window and close it.

document.getElementById("close-button").addEventListener('click', function (e) {
    const window = remote.getCurrentWindow();
    window.close();
});

Use as a templete

Ok, you understand all this now. Do I have to type all this in over and over again? No. You could just copy this folder over. The files you’ll need are:

  • main.js
  • index.html
  • index.js
  • package.json

That’s the four you’ll need.

And the folder called node_modules? We’ll let NPM handle that. Remember, NPM stored all the information in the package.json file. All we need to do is have NPM install the modules. Once the four files are in a folder go to the command prompt for that folder and use the following command.

npm install

NPM will now install all the items required.

Moving Forward

There it is. Four files to make a desktop application.

index.js and index.html are yours to do as you please. Go ahead and put whatever project you are working on. Add some CSS. Even BootStrap, or any other CSS framework or library.

There is also an NPM package that will let us bundle the whole Electron app up in a distributable package. That way the people using our app don’t need to have Node installed or need to know about Electron. We can produce these packages for Linus, MacOS or Windows on any of the three platforms. But that’s for a blog post for another day.

Resources

Electron JS

NPM JS

NodeJS