Getting started with electronjs
Tags: electronjs, node, javascript, vscode
Published: 2020-09-10 08:14:46

Objective: This guide will teach you how to develop and distribute an Electron.js application.
Audience: This guide is targeted at Electron beginners. It is strongly recommended that readers have at least fundamental knowledge of HTML, CSS and JavaScript with Node.js as the Electron framework is built around these items. 

# Introduction 
Electron is an open-source software framework developed and maintained by GitHub. It allows for the development of desktop GUI applications using web technologies: it combines the Chromium rendering engine and the Node.js runtime. [source](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwj_4L3b6dbrAhXczjgGHQPkAjQQmhMwJnoECA8QAg&url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FElectron_(software_framework)&usg=AOvVaw03lj-9a7uCcaAGrIE7qpJ-)

# Understanding Electron
If you found this guide by wanting to develop cross platform applications then you probably know that Electron.js does just that. You can easily develop and distribute applications for windows/macOS/linux with the same code (bear in mind this does not include android or iOS).

The question becomes, “How does Electron accomplish this?”. In short; Electron launches a headless [chromium](https://www.chromium.org/Home) browser which has access to the [Node.js API](https://nodejs.org/docs/latest/api/) via Electron’s own API. Which has plenty of use cases but, probably the biggest being is that your app can theoretically work without an internet connection, unless your code requires an internet connection.

If that was a bouncer that’s okay but, it’s important to understand the Electron combines the browser and Node.js to create this seamless development experience for us.

Electron is the main GUI framework behind several notable open-source projects including Atom, GitHub Desktop, Light Table, Visual Studio Code, and WordPress Desktop.

![Apps Built with Electron](https://dev-to-uploads.s3.amazonaws.com/i/0xyo4rag9z9b5kllucx4.jpg)

The above are some of the top apps, however you can go ahead and check out more app built with electron [here](https://www.electronjs.org/apps)

# Advantages
![advantages-electron](https://dev-to-uploads.s3.amazonaws.com/i/4rzf1s73a6ls2cg88bji.jpg)

------------------------------------------------------------------

# What you need to get started

Inspired by the getting started page in the Electron Documentation [Writing Your First Electron App](https://electronjs.org/docs/tutorial/first-app)

To develop desktop apps using Electron, I personally use [Visual Studio Code](https://code.visualstudio.com/), but most code editors that have a terminal included should work.
You'll also need to install the [NodeJS](https://nodejs.org/en/) runtime.

# Setting up your project
Now that you've got the right tools, let's get started setting up the project. To do so, you'll have to create a folder containing your project, and then open that folder using your code editor (VSCode in my case).
Then open up a terminal window into the newly created folder.

Then type in `npm init`. This will setup your `package.json` file.
You'll have to enter the following information:

- Package name: your project's name (lowercase and no spaces)
- Version: you can just hit enter for this one as it will default to 1.0.0
- Description: just enter some basic information about the purpose of your project
- Entry point: this one is quite important. It is the javascript file that will be executed when launching the project. By default it will name `index.js`, but you can change it to any name as it will handle all of our desktop application's windows. Many devs name it as `main.js` for electron apps.
- Test command: this is the command that will be executed when typing `npm test` in the terminal. you can hit enter to keep as it is, as later I will show you to set a command to run the electron app.

The remaining fields like Git Repository, Keywords, Author, license are just some information for when you'll publish your project on npmjs.

Once you confirm, a file called package.json will be created.
It should resemble something like this:

``` JSON
{
  "name": "sample-app-electron",
  "version": "1.0.0",
  "description": "A sample app using Electronjs",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "Milburn Gomes",
  "license": "ISC"
}

```

And to finish setting up your project, you'll have to install electron using npm. This is very easy, as all you have to do is type `npm install electron --save-dev` in the terminal window. Use `--save-dev` instead of `--save` so you can work on multiple apps with multiple electron version in the future.
Note that a package-lock.json file is created, but you don't have to worry about it.
Notice that you will also have electron in your package.json file under dependencies.

Also, while we are in package.json file you will need to one more change to run electron when you run `npm start` command. So inside your `scripts` tag add `start` property as `"start": "electron .",` because we want Electron to launch our application. The dot specifies the directory in which the Electron project is stored, which is just the root directory here, but if you want to store your project files somewhere else, you can adjust the directory. Code as shown below:

``` JSON
{
  "name": "sample-app-electron",
  "version": "1.0.0",
  "description": "A sample app using Electronjs",
  "main": "index.js",
  "scripts": {
    "start": "electron .",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "electron": "^10.1.1"
  }
}
```
Notice the script object, containing `start` which has the value of `electron .`, which means running the command `npm start` will execute your project. You can also add other scripts there. Read more about it [here](https://docs.npmjs.com/misc/scripts).

# Displaying a window

Now that everything is set up, we can start coding! Let's begin by creating the index.js file, that will handle our app's windows. So go ahead and create a new file and name it as `index.js` or if you have changed the name while running npm init command create file with that name.

Enter the following line of code: 
``` javascript
const { app, BrowserWindow } = require('electron')
```

I'll begin by referencing the electron package which we installed earlier. In this we are importing `app`, `BrowserWindow` from the reference to electron. `app` object will be used to detect app events, such as when the user launches the app and `BrowserWindow` lets us display an HTML document in the application window. 

I'll create a function createWindow(). It will be triggered when the app is launched, and inside of it I'll set up the win variable with some options defining the size in pixels of the window and since we are using node, set `nodeIntegration: true` inside `webPreferences`

Next specify the HTML file when the electron app window loads.

[Here](https://www.electronjs.org/docs/api/browser-window#new-browserwindowoptions) is a list of all the available options for BrowserWindow.

``` javascript
function createWindow () {
  // Create the browser window.
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true
    }
  })

  // and load the index.html of the app.
  win.loadFile('index.html')
}

```

And finally, when the app is ready call the function createWindow, as shown below:

``` javascript
app.whenReady().then(createWindow)
```

The final code in `index.js`should look like this:

``` javascript
const { app, BrowserWindow } = require('electron')

function createWindow () {
  // Create the browser window.
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      nodeIntegration: true
    }
  })

  // and load the index.html of the app.
  win.loadFile('index.html')
}

app.whenReady().then(createWindow)
```

# Displaying your HTML file

Now let's create the HTML file that is going to be displayed in the window. Create a new file index.html.

Inside it I'll just write a basic web page with Hello World! inside H1 tag:

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h1>Hello World!</h1>
</body>

</html>
```

Now you can just type `npm start` in the terminal, and you should see the HTML file inside a window as shown below:

![output](https://dev-to-uploads.s3.amazonaws.com/i/5avs4bluy2bo662eo4ke.jpg)

Till now we just used only plain HTML inside our webpage. To use CSS and JavaScript in your electron app, you will need to reference the CSS and JavaScript files in your index.html file. So go ahead and create two new files and name it as styles.css and script.js.

I have added bootstrap CDN and referenced the newly created CSS and JavaScript files. I've changed the text of H1 from Hello World! to Welcome Back! and also given an ID for H1 tag. Also I've added input field and a button. Another important thing to notice that I've added the [jquery.min.js](https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js) reference manually instead of CDN. If you try to run the electron app with jquery CDN, it will throw jquery not defined error. However, if you run just the html file it will work. This is because when jquery loads in electron, it loads as a module, it is not available globally hence the BrowserWindow is unable to access it and throws jquery not defined error. The index.html code is as follows:
``` HTML
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <script>window.$ = window.jQuery = require('./jquery.min.js');</script>
    <!-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> -->
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    <link rel="stylesheet" type="text/css" href="./styles.css" />
    <title>Document</title>
</head>

<body>
    <h1 id="welcomeUser">Welcome Back!</h1>
    <input id="user" placeholder="Enter your name here..."></input>
    <button id="submit">Submit</button>

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

</html>
```

For styling, I've added 10px margin for the entire document. Also for the html and body tag I've set the font size to 22px and color to dodgerblue. The styles.css code is as follows:
``` CSS
* {
    margin: 10px;
  }
  
  html,
  body {
    font-size: 22px;
    color: dodgerblue;
  }
```
For javascript logic, I'm taking the user input for the input field on click of the submit button and displaying in the H1 tag. The script.js code is as follows:
``` JavaScript
document.getElementById('submit').addEventListener('click', () => {
  if (document.getElementById('user').value) {
    document.getElementById('welcomeUser').innerHTML = `Hello, ${
      document.getElementById('user').value
    }!`;
  } else {
    document.getElementById('welcomeUser').innerHTML = `Hello, Guest!`;
  }
});

```

Now run the app by running the same command used earlier `npm start`

The output of the app is as follows:
![Output 1](https://dev-to-uploads.s3.amazonaws.com/i/piuem6k3wv4pfriamu3p.jpg)

On entering the name and clicking the submit button, you'll get the following:
![Output 2](https://dev-to-uploads.s3.amazonaws.com/i/sti69v7avwh621s3fqbe.jpg)

And now since you have created an app, you can go ahead and start building by using HTML, CSS and JavaScript. Because we're using NodeJS and Electron, you have the simplicity of creating websites combined with the power of Node. You can install modules from [npmjs](https://www.npmjs.com/) 

------------------------------------------------------------------
Another way to get started is to clone and run the code from the electron GitHub repository "electron-quick-start" by using the [electron/electron-quick-start repository](https://github.com/electron/electron-quick-start).

# Clone the repository
$ git clone https://github.com/electron/electron-quick-start
# Go into the repository
$ cd electron-quick-start
# Install dependencies
$ npm install
# Run the app
$ npm start

For a list of boilerplates and tools to kick-start your development process, see the [Boilerplates and CLIs documentation](https://www.electronjs.org/docs/tutorial/boilerplates-and-clis).
   
---

In order to set an icon, you need an image file. So get an image file and copy it in the project directory and set
`icon: 'icon.ico',` in the BrowserWindow in index.js file. The name of my icon file is icon with .ico extension. Note that you can use image of any type example: png, jpg but ico is preferred. Mac OS supports ico file for icon.

In order to make your run full screen, you need to specify `fullscreen: true,` in the BrowserWindow. But I'll be commenting it in the code.

If you want to open Developer Tools when the app runs, include `win.webContents.openDevTools();` in your index.js file. But I'll be commenting it in the code.

The index.js code is as follows:

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

// SET ENV
process.env.NODE_ENV = 'development';

function createWindow() {
  // Create the browser window.
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    icon: 'icon.ico',
    // fullscreen: true,
    webPreferences: {
      nodeIntegration: true,
    },
  });

  // and load the index.html of the app.
  win.loadFile('index.html');

  // Open the DevTools.
  // win.webContents.openDevTools();

  // Quit app when closed
  win.on('closed', function () {
    app.quit();
  });

  const mainMenu = Menu.buildFromTemplate(mainMenuTemplate);

  // Insert menu
  Menu.setApplicationMenu(mainMenu);
}

app.whenReady().then(createWindow);

// Create menu template
const mainMenuTemplate = [
  {
    label: 'File',
    submenu: [
      {
        label: 'New Window',
        accelerator: process.platform == 'darwin' ? 'Command+N' : 'Ctrl+N',
        click() {
          NewWindow();
        },
      },
      {
        label: 'Quit',
        accelerator: process.platform == 'darwin' ? 'Command+Q' : 'Ctrl+Q',
        click() {
          app.quit();
        },
      },
    ],
  },
];

// Handle Open New Window
function NewWindow() {
  console.log(`Create a New Window`);
  let addWindow = new BrowserWindow({
    width: 500,
    height: 500,
    title: 'New Window',
  });
  addWindow.loadURL(
    url.format({
      pathname: path.join(__dirname, 'New.html'),
      protocol: 'file:',
      slashes: true,
    })
  );
  // Handle garbage collection
  addWindow.on('close', function () {
    addWindow = null;
  });
}

// If mac, add empty object to menu
if (process.platform == 'darwin') {
  mainMenuTemplate.unshift({});
}

// Add dev tools, if not in prod
if (process.env.NODE_ENV !== 'production') {
  mainMenuTemplate.push({
    label: 'Developer Tools',
    submenu: [
      {
        label: 'Toggle DevTools',
        accelerator: process.platform == 'darwin' ? 'Command+I' : 'Ctrl+I',
        click(item, focusedWindow) {
          focusedWindow.toggleDevTools();
        },
      },
      {
        role: 'reload',
      },
    ],
  });
}

```
New.html file code is as follows:
``` HTML
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <script>window.$ = window.jQuery = require('./jquery.min.js');</script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
    <link rel="stylesheet" type="text/css" href="./styles.css" />
    <title>Document</title>
</head>

<body>
    <h1>Hello World!</h1>
</body>

</html>
```

Next, I'll be showing how to package the app!

There are several app packagers. I will show two of them `electron-packager` and `electron-builder`. The difference between them is that the former creates an simple executable file while the latter creates an installer which prompts user to select install location. 
First I will show you using `electron-packager`. In the terminal, run `npm install electron-packager --save-dev`. Once installed, add `"package-win": "electron-packager .",` inside of scripts in package.json.

Your package.json file should look like this:

``` JSON
{
  "name": "sample-app-electron",
  "version": "1.0.0",
  "description": "A sample app using Electronjs",
  "main": "index.js",
  "scripts": {
    "start": "electron .",
    "package-win": "electron-packager .",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "electron": "^10.1.1",
    "electron-packager": "^15.1.0"
  }
}
```

Now our app is ready to publish. Run the command in the terminal `npm run package-win`. Once it finishes executing the command you will see a new folder being created into the project directory `sample-app-electron-win32-x64` and inside this folder you will see `sample-app-electron.exe`, which is our electron app which we just developed. But there's a catch, if you navigate to `sample-app-electron-win32-x64\resources\app` you will see your source code. 

![Electron Packager 1](https://dev-to-uploads.s3.amazonaws.com/i/wveka77ro5y8u4estjnf.jpg)

This means that the source code is not protected. So in order to protect your code edit the `"package-win"` to `"package-win": "electron-packager . --asar",`
Along with this, I have also added some more useful options. One of them is to overwrite the application build folder if it already exists, platform is set to win32, icon is given the icon file, prune set to true gets rid of unwanted JavaScript files, out sets the output folder of the application build folder, and few more.

``` JSON
{
  "name": "sample-app-electron",
  "version": "1.0.0",
  "description": "A sample app using Electronjs",
  "main": "index.js",
  "scripts": {
    "start": "electron .",
    "package-win": "electron-packager . --overwrite --asar --platform=win32 --icon=icon.ico --prune=true --out=release-builds --version-string.CompanyName=Example --version-string.FileDescription=SampleApp --version-string.ProductName=\"SampleApp\"",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "electron": "^10.1.1",
    "electron-packager": "^15.1.0"
  }
}
```
Run the command in the terminal `npm run package-win`. Now if you navigate to `sample-app-electron\release-builds\SampleApp-win32-x64\resources` you will see a single file named `app.asar` which means that your code is protected.
 
![Electron Packager 2](https://dev-to-uploads.s3.amazonaws.com/i/jx8hhyem0jl0jlqmnhyl.jpg)


Next, run the command `npm install electron-builder --save-dev`. Then add in your package.json file `"productName": "SampleApp",`, `"build-installer": "electron-builder",` under scripts and create a text file and name it as license.txt. Add your license in this file. In this example I'll be adding just a sample text. Your license.txt file is as follows:

```
SampleApp

A sample app using Electronjs
```

Also add a build property as follows:
``` JSON
 "build": {
    "appId": "sample-app-electron",
    "win": {
      "target": [
        "nsis"
      ],
      "icon": "icon.ico",
      "requestedExecutionLevel": "requireAdministrator"
    },
    "nsis": {
      "installerIcon": "icon.ico",
      "uninstallerIcon": "icon.ico",
      "uninstallDisplayName": "SampleApp",
      "license": "license.txt",
      "oneClick": false,
      "allowToChangeInstallationDirectory": true
    }
  },
```
So finally your package.json file should look like this:

``` JSON
{
  "name": "sample-app-electron",
  "productName": "SampleApp",
  "version": "1.0.0",
  "description": "A sample app using Electronjs",
  "main": "index.js",
  "scripts": {
    "start": "electron .",
    "package-win": "electron-packager . --overwrite --asar --platform=win32 --icon=icon.ico --prune=true --out=release-builds --version-string.CompanyName=Example --version-string.FileDescription=SampleApp --version-string.ProductName=\"SampleApp\"",
    "build-installer": "electron-builder",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "build": {
    "appId": "sample-app-electron",
    "win": {
      "target": [
        "nsis"
      ],
      "icon": "icon.ico",
      "requestedExecutionLevel": "requireAdministrator"
    },
    "nsis": {
      "installerIcon": "icon.ico",
      "uninstallerIcon": "icon.ico",
      "uninstallDisplayName": "SampleApp",
      "license": "license.txt",
      "oneClick": false,
      "allowToChangeInstallationDirectory": true
    }
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "electron": "^10.1.1",
    "electron-packager": "^15.1.0",
    "electron-builder": "^22.8.0"
  }
}
```
Run the command `npm run build-installer`. You will notice a new folder named `dist` created which will contain the exe file named `SampleApp Setup 1.0.0.exe`. Also, if you navigate to `dist\win-unpacked\resources` you will see that your source code is protected as well. Now if you execute the exe file it should open the installer. Following are the screens at each click:

![Install Screen 1](https://dev-to-uploads.s3.amazonaws.com/i/ywiydwhyfgscux8loe7m.jpg)

![Install Screen 2](https://dev-to-uploads.s3.amazonaws.com/i/xz2nsiui42ddjyqayjpl.jpg)

![Install Screen 3](https://dev-to-uploads.s3.amazonaws.com/i/26m318b7cvgd4ha56dc1.jpg)

![Install Screen 4](https://dev-to-uploads.s3.amazonaws.com/i/emkgu85oaa24s0jhp1a8.jpg)

![Install Screen 5](https://dev-to-uploads.s3.amazonaws.com/i/plcek9sd5s89ty4ceuwx.jpg)

![Install Screen 6](https://dev-to-uploads.s3.amazonaws.com/i/k27u01894gmn6zf98e5w.jpg)

And there you go, you have successfully developed and is now ready to distribute an Electron.js application!

You can find the entire source code for this tutorial [here](https://github.com/MilburnGomes/sample-app-electron.git)

Also, don't forget to check out my other electron.js projects:
[Bitcoin Price Alert App](https://github.com/MilburnGomes/bitcoin-price-alert-app-electron)
[Note Taking App](https://github.com/MilburnGomes/note-app-electron)
[System Info App](https://github.com/MilburnGomes/system-info-app-electron)
[Tasks List App](https://github.com/MilburnGomes/taskslist-electron)

# In Conclusion: 
This guide should have given you a fundamental understanding of how Electron works. If you had trouble following this guide I suggest spending more time learning Node.js before jumping into Electron. If this guide was too simple, I highly suggest checking out the following resources:
[Electron Documentation](https://electronjs.org/docs)
[Electron Packager Documentation](https://github.com/electron-userland/electron-packager)
[Electron Builder](https://github.com/electron-userland/electron-builder)

Thank you!