Beginner’s Guide On Electron
The thought of building a cross-platform desktop application usually ends up in compromising on user experience, application features, ease of development etc. Building a desktop application is a great challenge for any application development professional because of the required platform-specific knowledge. If you want the application to run on different platforms then your knowledge requirements increase significantly due to the demanded environments.
But imagine a world where we could build performance driven, cross-platform desktop applications without doing much compromises. Is that something achievable or is it just the dream of a software developer? Well, let me take you through a platform that helps you build cross-platform desktop applications using JavaScript, HTML and CSS.
What is Electron?
Electron is a framework which uses Javascript, CSS and HTML for creating awesome desktop applications. Electron depends on nodejs and chromium. We can also use native node modules in electron. Electron is easy to build and supports cross-platform desktop applications. Let us explain how to get started with Electron.
1: Prerequisites
- Windows, Linux or Mac Os ( 64 bit is preferred because if we are using any native node modules, we may some time needs to convert/rebuild that to make compatible with Electron. Some native modules (example node sqlite3 ) doesn’t have a valid support on 32bit machines)
- Npm and nodejs installed.
2: Create some basic folders and files.
Move to your root directory (if not create one, say mydesktopapp) Let’s create three files (package.json, main.js ,index.html) as follows
Mydesktopapp
- package.json
- app (folder)
- main.js
- index.html
Let’s examine what all are these
3: Work on package.json
A : package.json
This file holds the app details, starting point of the app, lists the dependencies used etc. Let’s add some content to our package.json.
{
"name": "MyDeskApp",
"version": "0.0.1",
"description": "My first desktop app",
"main": "app/main.js",
"author": "Vishal <vishal@cubettech.com>",
"license": "CC0-1.0",
"scripts": {
"start": "./node_modules/.bin/electron ."
}
}
This is the basic content of package.json. Most of them are self explanatory. “script” here holds shortcut commands that can be used to control our app. The command used to start our app is “./node_modules/.bin/electron .” We can create a shortcut to that using the “start” in script tag. So we can use “npm start” command instead of “./node_modules/.bin/electron .” command to run our app. We can add more shortcuts as we move forward.
4: Install Electron
Installation is quite simple. Move to your root directory (say mydesktopapp) and then run the following command.
# Install as a development dependency
npm install electron –save-dev
# Install the `electron` command globally in your $PATH
npm install electron -g
Be patient, It will take some time to finish.
After successful installation check the package.json file , we can see some extra lines as follows.
"devDependencies": { "electron": "^1.6.2" }
This will get automatically added when we install electron. –save-dev will add these lines automatically to this package.json. Any native modules we installed later using –save-dev will get added under “devDependencies”.
If we install using –save then it will get added under “dependencies”.
After the installation, we can see a new “node_modules” inside our root folder. This is the installation folder where our electron is installed
Mydesktopapp
- package.json
- app (folder)
- main.js
- Index.html
- node_modules
Before running our app. We need to do some basic coding in our main.js and index.html.
5: Work on other basic files
A: main.js
In our package.json we mentioned that main file of our app is main.js inside the app folder. This file is responsible for starting and running our app. So let us create some basic code inside it. Just copy the following to main.js
const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;
const path = require('path');
const url = require('url');
let mainWindow;
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', function () {
createWindow();
});
function createWindow() {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 1024,
height: 600,
frame: true,
webPreferences: {
webSecurity: false,
plugins: true
}
});
// Open the DevTools.
mainWindow.webContents.openDevTools();
// and load the index.html of the app.
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}));
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null;
});
}
app.on('activate', function () {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow();
}
});
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q.
if (process.platform !== 'darwin') {
app.quit();
}
});
Main.js explanation:
We need to include our installed electron first and then make use of build in electron modules after that. Let us get familiar with some of the electron modules and functions that we used inside the main.js
- electron.app : Module to control application life. We can make use of this for the tasks to perform when our application is started , ready , active, quit and lot more
- electron.BrowserWindow : This is to handle the browser window creation and browser window related tasks. Electron is using chromium for the loading the app window.
- Path and Url : for loading other files like index.html
When our app is ready (after installation/start app ) it will emit ready event and on app.ready event emission, we creating a new browser window to load our app. The create Window function will make use of Browser Window module to create a new browser with the given values. Here we are using minimal options to create a window. There are lot more .
We can set our window to open the dev-tools for the sake of development. The webContents is used for rendering and controlling a web page. Opening dev-tools in web page is obtained by make use of webContents. webContents can do a lot more.
mainWindow.loadURL will load our index.html in the new browser window that we just created.
Now let us create a simple HTML for our index.html as follows.
B: index.html
Copy and paste the following code in index.html
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href='https://fonts.googleapis.com/css?family=Open+Sans:400,600,700,300' rel='stylesheet' type='text/css'>
<title>My desk app 0.0.1</title>
</head>
<body>
<main class="content-wraper" id="content-wraper">
<div class="content-blk">
Helo.. This is my first desktop app
</div>
</main>
<!-- Insert this line above script imports -->
<script>
if (typeof module === 'object') {
window.module = module;
module = undefined;
}
</script>
<!-- normal script imports etc -->
<!-- Insert this line after script imports -->
<script>
if (window.module) module = window.module;
</script>
<script type="text/javascript">
<!-- insert the js scripts -->
</script>
</body>
</html>
This is a simple html file. The only thing that unfamiliar here will be
“ <script>if (typeof module === ‘object’) {window.module = module; module = undefined;}</script>” .
This is just to load the jquery functions without any issue. We may face some issues on using jquery inside electron HTML. This piece of line will resolve that issue and we can include and use jquery after this.
6: Run our app
Now we have our three basic files package.json , main.js and index.html. Let’s start our first desktop app by simply using the below command in command prompt/terminal npm start Our app will get started.
Yes, that’s all. We have successfully installed and run our first desktop app using electron.
By this we have not only run our app but also gone through an important concept in electron app.
Ie the main process and render process. The electron apps is completely working on these process concept. Let us see what we have done so far in the concept of main and render process.
7: Main processes
The main process are responsible for starting and running our app. The files and codes that supports the browser creation, webpage creation , starting the app and backing the app running, building and packing the app, autoupdating the app etc will comes under main process. Some of such electron functions can only be used inside main processes.
8: Render processes
The render process are responsible for rendering the output or view in the browser event created by main process. This deals with the user interfaces of our app. Handles dom elements, Javascripts, other HTML (that needed for UI) etc. For example, we cannot access dom elements in main processes. Some of the electron functions can only be used inside render processes.
Some electron functions can be used both inside main and render process.
9: Main and render process in our app
Main.js is responsible starting and running our app and index.html is renders the output or view in the browser. So main.js in our app folder is the main process and index.html is the render process in our case.
We can include the rest of our app’s specific main process code in main.js. We can also put them in separate files and require them in main.js.
All HTML related items should in render process. We can include the rest of our app’s specific render process (UI related js, other HTML ) code in index.html. We can also put them in separate files and require them in index.html.
10: Communication between main and render process.
From this we know that some electron functions (electron api) can only be used inside main process and others in render process.
Now let’s think about a case. We need to create a new popup window in our main window when clicking a button in index.html.
We know we need “BrowserWindow” event for creating a new window. BrowserWindow will only work on main process. Our button click is from index.html (render process). Then how can we create a new window in main process when clicking a button in render process.
The only way is to inform the main process that button is clicked, create a new window. Main.js (our main process ) has to create this for us. But how our main process knows the button is clicked? We can think about a way by jquery. Write a jquery function for button click on main process and create the window. But this not possible because we cannot do any dom related functions in main process. So we cannot write a jquery in main process to trigger the click.Also if a main process wants to do some jquery related item, like showing a message in html, render process must do that for main process.
Then how to communicate between main process and render process?. We need a way to communicate with main process and render process. Inform main process that render process needs something and reply with result and vice versa. Electron uses IPC module (inter process communication) for the communication between a main process and render process.
Electron has two ipc modules.
- ipcMain (This is the module used in main process to communicate with render process. )
- ipcRender(This is the module used in render process to communicate with main process. )
Let’s examine ipcRender first. Modify our index.html
<main class="content-wraper" id="content-wraper">
<div class="content-blk">
Helo.. This is my first desktop app
<button id="loadnewwindow">Click to load new window</button>
<div id="message"></div>
</div>
</main>
Then add the following script at the bottom of index.html
<script type="text/javascript">
// Include the ipc module to communicate with the main process.
const ipcRenderer = require('electron').ipcRenderer;
const btnclick = document.getElementById('loadnewwindow');
btnclick.addEventListener('click', function () {
var arg = "secondparam";
// Send the info to the main process. We can pass any arguments as the second parameter.
ipcRenderer.send("btnclick", arg); // ipcRenderer.send will pass the information to the main process
});
</script>
Now we have sent a communication to the main process that a button is clicked and do necessary action.
Now let’s make some changes in our main process to receive this communication (ie main.js ).
const { ipcMain, BrowserWindow } = require('electron');
ipcMain.on("btnclick", function (event, arg) {
// Create a new window
var newWindow = new BrowserWindow({
width: 450,
height: 300,
show: false,
webPreferences: {
webSecurity: false,
plugins: true,
nodeIntegration: false
}
});
// Load an external URL (in this case, Facebook)
var facebookURL = "https://www.facebook.com";
newWindow.loadURL(facebookURL);
// Show the new window
newWindow.show();
// Inform the renderer process that the assigned task is finished
// Show a message in HTML
event.sender.send("btnclick-task-finished", "yes");
});
Receive the task finished reply from the main process and show a message in HTML. So in render process do the following.
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script type="text/javascript">
// ipcRenderer.on will receive the "btnclick-task-finished" info from the main process
ipcRenderer.on('btnclick-task-finished', function (event, param) {
$("#message").html("Loaded a popup"); // Show message using jQuery
});
</script>
Then run our app using npm start
This is how communication between main and render process occurs in Electron.
11: How to make use of remote module in render process for communication?
In Order to reduce the hardship in inter-process communication, electron introduced ‘remote’ module which helps to use the main process functions in render process also.
In our above, we can use the remote module to pop up a new window from render process itself instead of main process-render process to and fro communication. Following is an example for loading a new page in current browser window from render process itself.
var homeButton = document.getElementById("home");
const remote = require('electron').remote;
homeButton.onclick = function () {
var mainWindow = remote.getCurrentWindow();
mainWindow.loadURL('file://' + __dirname + '/home.ejs'); // load new page
};
12: Other interesting topics
We can come up later with some more and very important topics like
- How to load more main and render process other than main.js and index.html?
- How to use and rebuild native node modules in electron?
- How to set up a local db in electron ?
- How to build and pack electron app for distribution?
- How to overcome the cross-platform issues on packing electron?
- How to pack electron in windows machines?
- How to creating desktop shortcuts for an installed electron application?
- How to auto update an installed app when a new version is available?
- And some other interesting topics.
Hope you did get to know about Electron from this post. It’s just a beginner’s guide, we will discuss more about this topic through our upcoming blogs. Cubet Tech is adding in this all new technology to our stack. For more information Contact us thoughts our Facebook, Twitter or our LinkedIn.
Thanks.