Friday, June 26, 2020

How to create a desktop app from website in 10 minutes?



desktop application from website


Building a Cross Platform Desktop Application (i.e.. App that can run on Windows, Linux, and Mac os) helps to reduce the development time and cost. Electron is one of the best and known frameworks to develop desktop applications. 
Many famous applications like VS Code, Slack, Figma, etc are built on Electron.
The best part about Electron is, you need not learn any new language, you can simply write JavaScript, HTML, or use a framework like REACT, VUE, and ANGULAR and compile it to a desktop app, or If you have a website hosted you can simply provide the URL of the website to create a desktop application.
Today we will see how to create a desktop application from a website hosted on the web and some must-have features to get you started.

If you have no time or wanna know what we are going to build then I recommend clone/download my desktop-app-in-minutes repo and replace the https://www.blog.guidefather.in URL with your websites URL.

What we will cover?

  • What is electronJS?
  • Create a desktop app from the website URL.
  • Create a Custom Header in electron app.
  • Using npm modules in the electron app.
  • Managing app events 
  • Distribution of an electron app
  • Pros and Cons of electrons
app preview

What is electronJS?

With the help of ElectronJs one can build cross-platform desktop applications with HTML, JavaScript, and CSS. It was introduced in 2013 to make cross-platform text-editors, later its scope was extended to build other utility apps. Electron has chromium in it
Electron has two processes 
  • Main Process: It manages the bootstrapping the application and lifecycle events like starting, quitting, etc. This main process is responsible for interacting with the native GUI of the Operating System. It creates the GUI of your application.
  • Rendering Process: It is created by the main process and its main purpose is to render the UI.

Create a desktop app from the website URL.

Before proceeding you need to have node and npm install in your system.
Steps to create a desktop app.
  • Create a folder with the name you want and type following commands
    npm init -y
    npm i electron --save-dev
  • add a start script in package.json
    "start":"electron ."
 You can get the complete project code from my GitHub Repository.

const { app, BrowserWindow, Menu, shell } = require('electron');

function createWindow() {
const win = new BrowserWindow({
width: 1100,
height: 800,
webPreferences: {
nodeIntegration: true
}
})
// win.webContents.openDevTools() //Open dev tools

// To open the file from a local directory.
// win.loadFile('index.html')

//open url
win.loadURL("https://www.blog.guidefather.in")


}

//lauch view when electron is ready
app.whenReady().then(createWindow)

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})

// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})

   main.js

This will open https://www.blog.guidefather.in in an application, from which you can interact.
BrowserWindow runs its own renderer process. This renderer process will take the HTML, CSS, and JavaScript and render it to the window.

win.webContents.openDevTools()
It is used to open dev tools in the application for debugging purposes.

If you have the code in ANGULAR, REACT, VUE, or any other framework which can be compiled down to HTML, CSS, and JavaScript you can create an application by providing a path to the dist folder
win.loadFile("path_to_dist")
By using the above code you will have a basic desktop application.

Create a custom header in electron app

By writing the above code you will have a desktop application but with a default header of your operating system. You can override the default headers and create custom headers by using the MENU module of electron.

const menu = Menu.buildFromTemplate([{
label: "Menu",
submenu: [
{
label: "Disclaimer",
click() {
utility.openModel(win, "Disclaimer")
}
},
{
label: "View Article",
click() {
//open external links
shell.openExternal("https://www.blog.guidefather.in")
}
},
{ type: "separator" },//introduce a gap in menu
{
label: "Exit",
click() {
app.quit() //quit application
}
}
]

}, {
label: "History",
accelerator: "CommandOrControl+H", //shortcut
click() {
utility.openModel(win, "History")
}
}])
Menu.setApplicationMenu(menu)
By implementing the above code you will have a menu like this
Menu Preview
 Menu.buildFromTemplate takes an array of objects which will be displayed as the menu. Each Object has a mandatory field label which will be displayed as the title of the menu. You can have sub-menu using submenu inside each object.
To perform click event you have to declare a function click.
You can specify shortcut keys to perform the task by using an accelerator. As you can see I have used CommandOrControl+H to open the history tab.

Events 

app.quit() : This will close the application 
shell.openExternal() :  To open External links 
openModal: I've created a custom function to open models in utility.js
function openModel(parent, pageType) {
modal = new BrowserWindow({
width: 600,
height: 700,
title: 'Info',
frame: false,//remove headers
backgroundColor: '#2e2c29',
parent: parent,//to specify the parent
webPreferences: {
nodeIntegration: true
}
});
// modal.webContents.openDevTools()
switch (pageType) {
case "Disclaimer":
modal.loadFile("./src/info.html")
break;
case "History":
modal.loadFile("./src/history.html")
break;
}
modal.on('close', function () {
modal = null;
});
}

Using NPM module in the electron app.

You can use the NPM module in the electon app in the same way as you use in node.js, but the best part is if you specify nodeIntegration = true in BrowserWindow then you can access Node.js in HTML files.
To access Node.js in HTML file, simply declare a script tag in the HTML page and start writing Node.js 
<script>
const remote = require("electron").remote;
const utility = require("../utility")
document.querySelector("#close-info").addEventListener("click", function () {
remote.getCurrentWindow().close() //get current window and close it
})
utility.getHistory().then(history => {
history.forEach(d => {
document.getElementById("hist-row")
            .insertAdjacentHTML('beforeend',
                                  `<tr><td>${d[0]}</td><td>${d[1]}</td><tr>
                                `);
});
})
</script>

As you can see I have imported utility using require statement to call utility functions.

Managing App Events

You can monitor the events performed by the user in the application by app events. I've used this feature to monitor the history of the user by writing it to a CSV file.
win.webContents give access to the running process.
win.webContents.on("will-navigate", function (e, url) {
utility.writeHistory(url)
})

You can check all the option here
To specify the directory where to save the file I've used 
const historyPath= (app || remote.app).getPath("userData") + "/history.csv";
getpath will return the path depending on the operating system. If you don't specify this then your code may not runs all platforms.

Distribution of electron app

After development comes the most tricky part compiling the OS-specific builds. To build an application in electron I recommend using electron-builder
  • Install electron builder
    npm i electron-builder --save-dev
  • Add icons 
    create a folder in the project directory, name it build and place icon with the name of icon.png and dimension of 256 X 256.
  • Modify package.json, electron builder take the details from package.json file. 
    {
    "name": "gview",
    "version": "1.1.0",
    "description": "website to desktop app in 5 mins",
    "main": "main.js",
    "scripts": {
    "start": "electron .",
    "build:linux": "electron-builder --linux deb",
    "build:win": "electron-builder --win", "build:mac": "electron-builder --mac"
    },
    "keywords": [],
    "author": {
    "name": "Service",
    "email": "service.b@blog.guidefather.in"
    },
    "license": "ISC",
    "devDependencies": {
    "electron": "^9.0.5",
    "electron-builder": "^22.7.0"
    },
    "dependencies": {
    "csv-writer": "^1.6.0"
    },
    "homepage": "https://blog.guidefather.in",
    "nsis": {
    "deleteAppDataOnUninstall": true,
    "uninstallDisplayName": "app"
    }
    }
replace the details with you own.
  • run commands
    npm run build:linux for Linux
    npm  run build:win for windows
    npm  run build:mac for Mac
    for more details and info you can check the link 

Pros and Cons of electron App

PROS

  • You need not to learn an extra language or framework. If you have knowledge of HTML, CSS and JavaScript you can build cross-platform apps in few minutes.
  • Its has great documentation and APIs which help you achieve the desired results and access native APIs easily.
  • You can develop without worrying about platform compatibility.
  • NPM support, you have access to the huge libraries of npm, using which you can achieve anything.

CONS

  • Build size is huge, Even for small application build size is huge because it has the chromium engine built in it.
  • Hight CPU utilization, Electron consumes a high amount because it launches a separate instance of chromium every time a new window loads.
  • Build Complications, Building OS-specific installable may not give desired results. You will most likely face issues with icons, writing files, etc.. because each and every system behaves differently.

Conclusion 

ElectronJs is great if you are not developing something out of the box or CPU intensive apps. With nice documentation and support electronJs is still evolving. I recommend to clone my GitHub repo and check CPU utilization, build size etc.. and make sure electron is best for your need.

T̳h̳a̳n̳k̳ y̳o̳u̳