DEV Community

Cover image for Getting started with electronjs
MilburnGomes
MilburnGomes

Posted on

Getting started with electronjs

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

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 browser which has access to the Node.js 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

The above are some of the top apps, however you can go ahead and check out more app built with electron here

Advantages

advantages-electron


What you need to get started

Inspired by the getting started page in the Electron Documentation Writing Your First Electron App

To develop desktop apps using Electron, I personally use Visual Studio Code, but most code editors that have a terminal included should work.
You'll also need to install the NodeJS 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:

{
  "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:

{
  "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.

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:

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 is a list of all the available options for BrowserWindow.

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:

app.whenReady().then(createWindow)

The final code in index.jsshould look like this:

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:

<!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

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 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:

<!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:

* {
    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:

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

On entering the name and clicking the submit button, you'll get the following:
Output 2

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


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.

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.


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:

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:

<!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:

{
  "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

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.

{
  "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

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:

 "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:

{
  "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

Install Screen 2

Install Screen 3

Install Screen 4

Install Screen 5

Install Screen 6

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

Also, don't forget to check out my other electron.js projects:
Bitcoin Price Alert App
Note Taking App
System Info App
Tasks List App

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
Electron Packager Documentation
Electron Builder

Thank you!

Top comments (0)