Ideas2IT rewards key players with 1/3rd of the Company in New Initiative.  Read More >
Back to Blogs

Building Cross-Platform Applications with ElectronJS

There is a wide range of frameworks for building web applications like Ruby on Rails, Django, Angular, and more. Similarly, there are several frameworks for building native desktop applications like Microsoft Visual Studio and Cocoa. But, the desktop is not a single unit. There are multiple Operating Systems - Microsoft Windows, Linux, and macOS at the topmost level. The frameworks for Desktop applications are OS-specific and at times even specific to the version of the OS. For applications used by a wide array of audiences, it is preferred that the application runs on all platforms. But, building separate applications for each platform could lead to duplicated effort. It also adds to development costs and could make maintenance quite cumbersome.

Each platform has its own unique capabilities and quirks. But these quirks and requirements are evident in language optimizations, API availability, toolchain preferences, and many more dependencies that pop up when you build native applications. So, building a cross-platform application that worked across all desktop platforms as well as on the web was nearly impossible, until Electron came along.

What Is Electron.js?

Electron.js was first developed by the team at Atom to make cross-platform development easier for their application. It was first founded on 15th July 2013. It was initially named Atom Shell. It was then open-sourced in May 2014 and is being maintained by GitHub since then.

Electron docs states "ElectronJS is a runtime framework that allows the user to create desktop-suite applications with HTML5, CSS, and JavaScript".

Simply put, web developers can use the combination of Chromium, the open-source version of The Google Chrome browser, and the Node.js JavaScript runtime and wrap their existing web applications with Electron.js to build desktop applications and generate installers for Windows, macOS, and Linux OS platforms. With this, desktop app development is no longer the exclusive capability of C++, C#, or Java developers. Using Electron.js, web developers can easily build and roll out industry-standard desktop applications.

Getting started with Electron.js

The Electron framework combines the Chromium rendering engine and the Node. js runtime. So, to build an application using Electron, you will need a basic working knowledge of Node.js. You do not need the platform native skills unless you are planning to build something really complex. Any web application that is written in a web tech stack can run on Electron.js. Similarly, any Node.js application you write can utilize this technology. The application can be designed for a single browser and can run on all desktop platforms. What is essential is that the application you build will have a file system of Node.js APIs.

Electron.js uses the npm module which is usually used for most JavaScript frameworks and has a native configuration for dialogs and notifications. That is why users do not need to add separate configurations while installing Electron.js applications on their desktops. Additionally, it also offers auto-updating and crash-reporting. Activities like crash reporting, debugging and profiling are done by Chromium.

Architecture of Electron.js

While developing a cross-platform application, you are basically building an application that will run on someone else’s computer. You are completely unaware of the OS or the OS version your users have while installing the application or running the application on a web browser. So the Electron.js framework is built with technologies that are universally compatible with most of the platforms. This way, the application can rely on and utilize the features available on the user's platform.

The Electron.js framework consists of 3 components:

  1. The open-source foundation for Google Chrome — Chromium’s rendering library called Libchromiumcontent.
  2. An open-source JavaScript runtime that enables JavaScript to run outside the browser — Node.js
  3. An open-source JavaScript engine written in C++ and JavaScript — v8 javascript engine

Prerequisites for Electron.js

To get started with Electron.js, you will require the following:

  • NodeJs & NPM : latest version
  • A code editor

You could choose to work with Electron Forge — an open-source tool for creating, publishing, and installing modern Electron applications. It is pretty functional and an easy tool. But if you are already accustomed to working with Node.js, you could go that route as well.

Create a folder on your PC. Open cmd, and run npm init. Enter the details of the project for the generated package.json. Now, all we need is Electron JS. Electron JS is a dev dependency, and it should be installed globally. Install it with the help of npm install -g electron --only=dev. Once installed, the package.json should have Electron as a devDependency. (If not, please add it manually).

"devDependencies": {

"electron": "^10.1.3"
}

In Electron JS, there are two processes. One is the main process and the other is the renderer process.

Main Process

In Electron, the process that runs package.json's main script is called the main process. The script that runs in the main process can display a GUI by creating web pages. An Electron app always has only one main process.

Renderer Process

Since Electron uses Chromium for displaying web pages, it also uses Chromium's multi-process architecture. Each web page in Electron runs in its own process and is called the renderer process.

To communicate between the main and renderer processes, Electron provides us the support called Inter-Process Communication.

  • ipcMain: It listens to the events from the renderer processes.

// In main process.

const { ipcMain } = require('electron')

ipcMain.on('synchronous-message', (event, arg) => {

console.log(arg) // prints "ping"

event.returnValue = 'pong'

})

  • ipcRenderer: Communicates asynchronously from a renderer process to the main process.

// In renderer process (web page).

const { ipcRenderer } = require('electron')

console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"

Steps for building an application in Electron.js

Step:1

Create a main.js file in the project directory, and it should be mentioned in package.json's main property. If it is not added in the process of npm init, please add it manually.

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

const url = require('url')

const path = require('path')


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.loadURL(url.format ({

pathname: path.join(__dirname, 'src/index.html'),

protocol: 'file:',

slashes: true

}))


// Open the DevTools.

win.webContents.openDevTools()


}


// Once our app is ready, we create an window and load index.html

app.whenReady().then(createWindow)


// on mac, processes will be running until user close it with cmd + q

app.on('window-all-closed', () => {

if (process.platform !== 'darwin') {

app.quit()

}

})


// When app is active, At least one window should be open.

app.on('activate', () => {

if (BrowserWindow.getAllWindows().length === 0) {

createWindow()

}

})

Step:2

If you notice the win.loadURL(), we load index.js, which lies in the src folder. Create an src folder inside our app dir. Here, create index.html, index.js, and index.scss.

Before you create them, take a step back and look at what you might require for the further steps.

For example, if you want to create a UI with a form that gets the date from the user and submits it, you will need jQuery, bootstrap, and a data-picker (js-datepicker).

npm install --save bootstrap

npm install --save jquery

npm install --save js-datepicker

Create index.js, and add all the required packages you need for your application.

let $ = jQuery = require('jquery');

const datepicker = require('js-datepicker')


let date = datepicker("#mydate",{

formatter: (input, date, instance) => {

input.value = getFormattedDate(date)

}

})


$("form").submit(e=>{

e.preventDefault();

let date = $("#mydate").val();

console.log("picked date", date)

})


function getFormattedDate(date) {

return ((date.getMonth() > 8) ? (date.getMonth() + 1) : ('0' + (date.getMonth() + 1)))

+ '-' + ((date.getDate() > 9) ? date.getDate() : ('0' + date.getDate()))

+ '-' + date.getFullYear()

}

Step:3

Now, create an index.html and load index.js into it.

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1.0">

<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />

<!-- <link rel="stylesheet" href="./bootstrap.min.css"> -->

<!--If import scss is not working please try adding bootsrap manually from node modules-->

<link rel="stylesheet" href="./index.scss">

<link rel="stylesheet" href="../node_modules/js-datepicker/dist/datepicker.min.css">

<title>Dowload File</title>

</head>

<body>

<div >

<h2>Dowload File</h2>

<form>

<div >

<label for="mydate">Date :</label>

<div style="position:relative">

<input type="text" id="mydate" data-date-format="dd/mm/yyyy" placeholder="Select a Date">

</div>

</div>

<button type="submit" >Submit</button>

</form>

</div>



</body>

</html>index.scss
SCSS

@import "~bootstrap/scss/bootstrap";


body{

background-color: #eee;

margin: auto;

}

.center {

margin: auto;

margin-top: 25px;

width: 50%;

border-radius: 25px;

padding: 10px;

}

Step: 4

In order to send the selected date to the main process, you will need ipcMain and ipcRenderer in main.js and index.js respectively.

//// Modification in index.js /////


// require ipcRenderer in index.js

const {ipcRenderer} = require('electron')


// modify form submit listener

$("form").submit(e=>{

e.preventDefault();

let date = $("#mydate").val();

console.log("picked date", date)

ipcRenderer.send("object-date", date);

})


/// modifications in main.js ///

// ipcMain is already required in main.js

// listener to pick the date

ipcMain.on("object-date",(e, date)=>{

console.log("selected date", date);

})

Step: 5

To run the app, you need to add script configuration in the application package.json.

JSON

"scripts": {

"start": "electron ."

}

That's all!

Your application is ready!

It is now time to run the application. Open your cmd and cd to project dir. Then, run npm run start. Now, you have our standalone app running. In order to enable your users to download, install and run your application, you need to build package installers for every platform. I have elaborated the steps for building a .exe file here. You can follow the same steps and use the electron.js documentation to build package installers for other OSes.

Building a .exe File

In order to execute the app you created, add another dev dependency called electron builder and script configurations. Run npm install electron-builder --only=dev and change your package.json's script:

{

.......



"main": "main.js",

"scripts": {

"start": "electron .",

"dist": "electron-builder"

},



.......

// now your dependencies will look like this.



"dependencies": {

"dotenv": "^8.2.0",

"jquery": "^3.5.1",

"js-datepicker": "^5.16.0"

},

"devDependencies": {

"electron": "^10.1.3",

"electron-builder": "^22.8.1"

}

}

Also, we need to write the build configuration in package.json:

{

........



"build": {

"appId": "app-name",

"win": {

"target": [

"nsis"

],

"icon": "src/icon/win.ico",

"requestedExecutionLevel": "requireAdministrator"

},

"nsis": {

"installerIcon": "src/icon/win.ico",

"uninstallerIcon": "src/icon/win.ico",

"uninstallDisplayName": "downloadClient",

"license": "license.txt",

"oneClick": false,

"allowToChangeInstallationDirectory": true

}



........

}

To check the build configurations of package installers for other OSs, check the Electron.js docs.

Now, run npm run dist. In a couple of minutes, you should be having your software ready in the dist folder.

That's all!

Your software is ready to install.

Happy coding!

Ideas2IT

Are you looking to build a great product or service? Do you foresee technical challenges? If you answered yes to the above questions, then you must talk to us. We are a world-class custom .NET development company. We take up projects that are in our area of expertise. We know what we are good at and more importantly what we are not. We carefully choose projects where we strongly believe that we can add value. And not just in engineering but also in terms of how well we understand the domain. Book a free consultation with us today. Let’s work together

Ideas2IT Team

Connect with Us

We'd love to brainstorm your priority tech initiatives and contribute to the best outcomes.