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.
The above are some of the top apps, however you can go ahead and check out more app built with electron here
Advantages
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 asmain.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.js
should 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:
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:
On entering the name and clicking the submit button, you'll get the following:
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.
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.
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:
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)