Author: saqibkhan

  • Webview

    The webview tag is used to embed the ‘guest’ content like web pages in your Electron app. This content is contained within the webview container. An embedded page within your app controls how this content will be displayed.

    The webview runs in a separate process than your app. To ensure security from malicious content, the webview doesn’t have same permissions as your web page. This keeps your app safe from the embedded content. All interactions between your app and the embedded page will be asynchronous.

    Let us consider an example to understand the embedding of an external webpage in our Electron app. We will embed the tutorialspoint website in our app on the right side. Create a new main.js file with the following content −

    const {app, BrowserWindow} = require('electron')
    const url = require('url')
    const path = require('path')
    
    let win
    
    function createWindow() {
       win = new BrowserWindow({width: 800, height: 600})
       win.loadURL(url.format ({
    
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
    })) } app.on('ready', createWindow)

    Now that we have set up our main process, let us create the HTML file that will embed the tutorialspoint website. Create a file called index.html with the following content −

    <!DOCTYPE html>
    <html>
       <head>
    
      &lt;meta charset = "UTF-8"&gt;
      &lt;title&gt;Menus&lt;/title&gt;
    </head> <body>
      &lt;div&gt;
         &lt;div&gt;
            &lt;h2&gt;We have the website embedded below!&lt;/h2&gt;
         &lt;/div&gt;
         &lt;webview id = "foo" src = "https://www.tutorialspoint.com/" style = 
            "width:400px; height:480px;"&gt;
            &lt;div class = "indicator"&gt;&lt;/div&gt;
         &lt;/webview&gt;
      &lt;/div&gt;
      
      &lt;script type = "text/javascript"&gt;
         // Event handlers for loading events.
         // Use these to handle loading screens, transitions, etc
         onload = () =&gt; {
            const webview = document.getElementById('foo')
            const indicator = document.querySelector('.indicator')
            const loadstart = () =&gt; {
               indicator.innerText = 'loading...'
            }
            const loadstop = () =&gt; {
               indicator.innerText = ''
            }
            webview.addEventListener('did-start-loading', loadstart)
            webview.addEventListener('did-stop-loading', loadstop)
         }
      &lt;/script&gt;
    </body> </html>

    Run the app using the following command −

    $ electron ./main.js
    

    The above command will generate the following output −

    Webview

    The webview tag can be used for other resources as well. The webview element has a list of events that it emits listed on the official docs. You can use these events to improve the functionality depending on the things that take place in the webview.

    Whenever you are embedding scripts or other resources from the Internet, it is advisable to use webview. This is recommended as it comes with great security benefits and does not hinder normal behaviour.

  • Notifications

    Electron provides native notifications API only for MacOS. So we are not going to use that, instead we’ll be using a npm module called node-notifier. It allows us to notify users on Windows, MacOS and Linux.

    Install the node-notifier module in your app folder using the following command in that folder −

    $ npm install --save node-notifier
    

    Let us now create an app that has a button which will generate a notification every time we click on this button.

    Create a new main.js file and enter the following code in it −

    const {app, BrowserWindow} = require('electron')
    const url = require('url')
    const path = require('path')
    
    let win
    
    function createWindow() {
       win = new BrowserWindow({width: 800, height: 600})
       win.loadURL(url.format ({
    
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
    })) } app.on('ready', createWindow)

    Let us now create our webpage and script that will trigger the notification. Create a new index.html file with the following code −

    <!DOCTYPE html>
    <html>
       <head>
    
      &lt;meta charset = "UTF-8"&gt;
      &lt;title&gt;Menus&lt;/title&gt;
    </head> <body>
      &lt;button type = "button" id = "notify" name = "button"&gt;
         Click here to trigger a notification!&lt;/button&gt;
      &lt;script type = "text/javascript"&gt;
         const notifier = require('node-notifier')
         const path = require('path');
         
         document.getElementById('notify').onclick = (event) =&gt; {
            notifier.notify ({
               title: 'My awesome title',
               message: 'Hello from electron, Mr. User!',
               icon: path.join('','/home/ayushgp/Desktop/images.png'),  // Absolute path 
                  (doesn't work on balloons)
               sound: true,  // Only Notification Center or Windows Toasters
               wait: true    // Wait with callback, until user action is taken 
               against notification
            
            }, function (err, response) {
               // Response is response from notification
            });
            notifier.on('click', function (notifierObject, options) {
               console.log("You clicked on the notification")
            });
            notifier.on('timeout', function (notifierObject, options) {
               console.log("Notification timed out!")
            });
         }
      &lt;/script&gt;
    </body> </html>

    The notify method allows us to pass it an objectwith information like the title, message, thumbnail, etc. which help us customize the notification. We can also set some event listeners on the notification.

    Now, run the app using the following command −

    $ electron ./main.js
    

    When you click on the button that we created, you will see a native notification from your operating system as shown in the following screenshot −

    Notification

    We have also handled the events wherein, the user clicks the notification or the notification times out. These methods help us make the app more interactive if its running in the background.

  • System Tray

    System tray is a menu outside of your application window. On MacOS and Ubuntu, it is located on the top right corner of your screen. On Windows it is on the bottom right corner. We can create menus for our application in system trays using Electron.

    Create a new main.js file and add the following code to it. Have a png file ready to use for the system tray icon.

    const {app, BrowserWindow} = require('electron')
    const url = require('url')
    const path = require('path')
    
    let win
    
    function createWindow() {
       win = new BrowserWindow({width: 800, height: 600})
       win.loadURL(url.format ({
    
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
    })) } app.on('ready', createWindow)

    After having set up a basic browser window, we will create a new index.html file with the following content −

    <!DOCTYPE html>
    <html>
       <head>
    
      &lt;meta charset = "UTF-8"&gt;
      &lt;title&gt;Menus&lt;/title&gt;
    </head> <body>
      &lt;script type = "text/javascript"&gt;
         const {remote} = require('electron')
         const {Tray, Menu} = remote
         const path = require('path')
         let trayIcon = new Tray(path.join('','/home/ayushgp/Desktop/images.png'))
         const trayMenuTemplate = &#91;
            {
               label: 'Empty Application',
               enabled: false
            },
            
            {
               label: 'Settings',
               click: function () {
                  console.log("Clicked on settings")
               }
            },
            
            {
               label: 'Help',
               click: function () {
                  console.log("Clicked on Help")
               }
            }
         ]
         
         let trayMenu = Menu.buildFromTemplate(trayMenuTemplate)
         trayIcon.setContextMenu(trayMenu)
      &lt;/script&gt;
    </body> </html>

    We created the tray using the Tray submodule. We then created a menu using a template and further attached the menu to our tray object.

    Run the application using the following command −

    $ electron ./main.js
    

    When you run the above command, check your system tray for the icon you used. I used a smiley face for my application. The above command will generate the following output −

    tray
  •  Menus

    The desktop apps come with two types of menus – the application menu(on the top bar) and a context menu(right-click menu). We will learn how to create both of these in this chapter.

    We will be using two modules – the Menu and the MenuItem modules. Note that the Menu and the MenuItem modules are only available in the main process. For using these modules in the renderer process, you need the remote module. We will come across this when we create a context menu.

    Now, let us create a new main.js file for the main process −

    const {app, BrowserWindow, Menu, MenuItem} = require('electron')
    const url = require('url')
    const path = require('path')
    
    let win
    
    function createWindow() {
       win = new BrowserWindow({width: 800, height: 600})
       win.loadURL(url.format ({
    
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
    })) } const template = [ {
      label: 'Edit',
      submenu: &#91;
         {
            role: 'undo'
         },
         {
            role: 'redo'
         },
         {
            type: 'separator'
         },
         {
            role: 'cut'
         },
         {
            role: 'copy'
         },
         {
            role: 'paste'
         }
      ]
    }, {
      label: 'View',
      submenu: &#91;
         {
            role: 'reload'
         },
         {
            role: 'toggledevtools'
         },
         {
            type: 'separator'
         },
         {
            role: 'resetzoom'
         },
         {
            role: 'zoomin'
         },
         {
            role: 'zoomout'
         },
         {
            type: 'separator'
         },
         {
            role: 'togglefullscreen'
         }
      ]
    }, {
      role: 'window',
      submenu: &#91;
         {
            role: 'minimize'
         },
         {
            role: 'close'
         }
      ]
    }, {
      role: 'help',
      submenu: &#91;
         {
            label: 'Learn More'
         }
      ]
    } ] const menu = Menu.buildFromTemplate(template) Menu.setApplicationMenu(menu) app.on('ready', createWindow)

    We are building a menu from a template here. This means that we provide the menu as a JSON to the function and it will take care of the rest. Now we have to set this menu as the Application menu.

    Now create an empty HTML file called index.html and run this application using −

    $ electron ./main.js
    

    On the normal position of application menus, you will see a menu based on the above template.

    Application Menus

    We created this menu from the main process. Let us now create a context menu for our app. We will do this in our HTML file −

    <!DOCTYPE html>
    <html>
       <head>
    
      &lt;meta charset = "UTF-8"&gt;
      &lt;title&gt;Menus&lt;/title&gt;
    </head> <body>
      &lt;script type = "text/javascript"&gt;
         const {remote} = require('electron')
         const {Menu, MenuItem} = remote
         const menu = new Menu()
         // Build menu one item at a time, unlike
         menu.append(new MenuItem ({
            label: 'MenuItem1',
            click() { 
               console.log('item 1 clicked')
            }
         }))
         
         menu.append(new MenuItem({type: 'separator'}))
         menu.append(new MenuItem({label: 'MenuItem2', type: 'checkbox', checked: true}))
         menu.append(new MenuItem ({
            label: 'MenuItem3',
            click() {
               console.log('item 3 clicked')
            }
         }))
         // Prevent default action of right click in chromium. Replace with our menu.
         window.addEventListener('contextmenu', (e) =&gt; {
            e.preventDefault()
            menu.popup(remote.getCurrentWindow())
         }, false)
      &lt;/script&gt;
    </body> </html>

    We imported the Menu and MenuItem modules using the remote module; then, we created a menu and appended our menuitems to it one by one. Further, we prevented the default action of right-click in chromium and replaced it with our menu.

    Context Menu

    The creation of menus in Electron is a very simple task. Now you can attach your event handlers to these items and handle the events according to your needs.

  •  System Dialogs

    It is very important for any app to be a user-friendly one. As a result you should not create dialog boxes using alert() calls. Electron provides a pretty good interface to accomplish the task of creating dialog boxes. Let us have a look at it.

    Electron provides a dialog module that we can use for displaying native system dialogs for opening and saving files, alerting, etc.

    Let us directly jump into an example and create an app to display simple textfiles.

    Create a new main.js file and enter the following code in it −

    const {app, BrowserWindow} = require('electron') 
    const url = require('url') 
    const path = require('path') 
    const {ipcMain} = require('electron')  
    
    let win  
    
    function createWindow() { 
       win = new BrowserWindow({width: 800, height: 600}) 
       win.loadURL(url.format ({ 
    
      pathname: path.join(__dirname, 'index.html'), 
      protocol: 'file:', 
      slashes: true 
    })) } ipcMain.on('openFile', (event, path) => { const {dialog} = require('electron') const fs = require('fs') dialog.showOpenDialog(function (fileNames) {
      
      // fileNames is an array that contains all the selected 
      if(fileNames === undefined) { 
         console.log("No file selected"); 
      
      } else { 
         readFile(fileNames&#91;0]); 
      } 
    }); function readFile(filepath) {
      fs.readFile(filepath, 'utf-8', (err, data) =&gt; { 
         
         if(err){ 
            alert("An error ocurred reading the file :" + err.message) 
            return 
         } 
         
         // handle the file content 
         event.sender.send('fileData', data) 
      }) 
    } }) app.on('ready', createWindow)

    This code will pop open the open dialog box whenever our main process recieves a ‘openFile’ message from a renderer process. This message will redirect the file content back to the renderer process. Now, we will have to print the content.

    Now, create a new index.html file with the following content −

    <!DOCTYPE html> 
    <html> 
       <head> 
    
      &lt;meta charset = "UTF-8"&gt; 
      &lt;title&gt;File read using system dialogs&lt;/title&gt; 
    </head> <body>
      &lt;script type = "text/javascript"&gt; 
         const {ipcRenderer} = require('electron') 
         ipcRenderer.send('openFile', () =&gt; { 
            console.log("Event sent."); 
         }) 
         
         ipcRenderer.on('fileData', (event, data) =&gt; { 
            document.write(data) 
         }) 
      &lt;/script&gt; 
    </body> </html>

    Now whenever we run our app, a native open dialog box will pop up as shown in the following screenshot −

    Open Dialog

    Once we select a file to display, its contents will be displayed on the app window −

    File Read Using Dialog

    This was just one of the four dialogs that Electron provides. They all have similar usage though. Once you learn how to do it using showOpenDialog, then you can use any of the other dialogs.

    The dialogs having the same functionality are −

    • showSaveDialog([browserWindow, ]options[, callback])
    • showMessageDialog([browserWindow, ]options[, callback])
    • showErrorDialog(title, content)
  • Inter Process Communication

    Electron provides us with 2 IPC (Inter Process Communication) modules called ipcMain and ipcRenderer.

    The ipcMain module is used to communicate asynchronously from the main process to renderer processes. When used in the main process, the module handles asynchronous and synchronous messages sent from a renderer process (web page). The messages sent from a renderer will be emitted to this module.

    The ipcRenderer module is used to communicate asynchronously from a renderer process to the main process. It provides a few methods so you can send synchronous and asynchronous messages from the renderer process (web page) to the main process. You can also receive replies from the main process.

    We will create a main process and a renderer process that will send each other messages using the above modules.

    Create a new file called main_process.js with the following contents −

    const {app, BrowserWindow} = require('electron')
    const url = require('url')
    const path = require('path')
    const {ipcMain} = require('electron')
    
    let win
    
    function createWindow() {
       win = new BrowserWindow({width: 800, height: 600})
       win.loadURL(url.format ({
    
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
    })) } // Event handler for asynchronous incoming messages ipcMain.on('asynchronous-message', (event, arg) => { console.log(arg) // Event emitter for sending asynchronous messages event.sender.send('asynchronous-reply', 'async pong') }) // Event handler for synchronous incoming messages ipcMain.on('synchronous-message', (event, arg) => { console.log(arg) // Synchronous event emmision event.returnValue = 'sync pong' }) app.on('ready', createWindow)

    Now create a new index.html file and add the following code in it.

    <!DOCTYPE html>
    <html>
       <head>
    
      &lt;meta charset = "UTF-8"&gt;
      &lt;title&gt;Hello World!&lt;/title&gt;
    </head> <body>
      &lt;script&gt;
         const {ipcRenderer} = require('electron')
         // Synchronous message emmiter and handler
         console.log(ipcRenderer.sendSync('synchronous-message', 'sync ping')) 
         // Async message handler
         ipcRenderer.on('asynchronous-reply', (event, arg) =&gt; {
            console.log(arg)
         })
         // Async message sender
         ipcRenderer.send('asynchronous-message', 'async ping')
      &lt;/script&gt;
    </body> </html>

    Run the app using the following command −

    $ electron ./main_process.js
    

    The above command will generate the following output −

    // On your app console
    Sync Pong
    Async Pong
    
    // On your terminal where you ran the app
    Sync Ping
    Async Ping
    

    It is recommended not to perform computation of heavy/ blocking tasks on the renderer process. Always use IPC to delegate these tasks to the main process. This helps in maintaining the pace of your application.

  • Native Node Libraries

    We used a node module, fs, in the previous chapter. We will now look at some other node modules that we can use with Electron.

    OS module

    Using the OS module, we can get a lot of information about the system our application is running on. Following are a few methods that help while the app is being created. These methods help us customize the apps according to the OS that they are running on.

    Sr.NoFunction & Description
    1os.userInfo([options])The os.userInfo() method returns information about the currently effective user. This information can be used to personalize the application for the user even without explicitly asking for information.
    2os.platform()The os.platform() method returns a string identifying the operating system platform. This can be used to customize the app according to the user OS.
    3os.homedir()The os.homedir() method returns the home directory of the current user as a string. Generally, configs of all users reside in the home directory of the user. So this can be used for the same purpose for our app.
    4os.arch()The os.arch() method returns a string identifying the operating system CPU architecture. This can be used when running on exotic architectures to adapt your application for that system.
    5os.EOLA string constant defining the operating system-specific end-ofline marker. This should be used whenever ending lines in files on the host OS.

    Using the same main.js file and the following HTML file, we can print these properties on the screen −

    <html>
       <head>
    
      &lt;title&gt;OS Module&lt;/title&gt;
    </head> <body>
      &lt;script&gt;
         let os = require('os')
         document.write('User Info: ' + JSON.stringify(os.userInfo()) + '&lt;br&gt;' + 
            'Platform: ' + os.platform() + '&lt;br&gt;' + 
            'User home directory: ' +  os.homedir() + '&lt;br&gt;' + 
            'OS Architecture: ' + os.arch() + '&lt;br&gt;')
      &lt;/script&gt;
    </body> </html>

    Now run the app using the following command −

    $ electron ./main.js
    

    The above command will generate the following output −

    User Info: {"uid":1000,"gid":1000,"username":"ayushgp","homedir":"/home/ayushgp",
       "shell":"/usr/bin/zsh"}
    Platform: linux
    User home directory: /home/ayushgp
    OS Architecture: x64
    

    Net Module

    The net module is used for network related work in the app. We can create both servers and socket connections using this module. Generally, the use of wrapper module from npm is recommended over the use of the net module for networking related tasks.

    The following tables lists down the most useful methods from the module −

    Sr.NoFunction & Description
    1net.createServer([options][, connectionListener])Creates a new TCP server. The connectionListener argument is automatically set as a listener for the ‘connection’ event.
    2net.createConnection(options[, connectionListener])A factory method, which returns a new ‘net.Socket’ and connects to the supplied address and port.
    3net.Server.listen(port[, host][, backlog][, callback])Begin accepting connections on the specified port and host. If the host is omitted, the server will accept connections directed to any IPv4 address.
    4net.Server.close([callback])Finally closed when all connections are ended and the server emits a ‘close’ event.
    5net.Socket.connect(port[, host][, connectListener])Opens the connection for a given socket. If port and host are given, then the socket will be opened as a TCP socket.

    The net module comes with a few other methods too. To get a more comprehensive list, see this.

    Now, let us create an electron app that uses the net module to create connections to the server. We will need to create a new file, server.js −

    var net = require('net');
    var server = net.createServer(function(connection) { 
       console.log('Client Connected');
       
       connection.on('end', function() {
    
      console.log('client disconnected');
    }); connection.write('Hello World!\r\n'); connection.pipe(connection); }); server.listen(8080, function() { console.log('Server running on http://localhost:8080'); });

    Using the same main.js file, replace the HTML file with the following −

    <html>
       <head>
    
      &lt;title&gt;net Module&lt;/title&gt;
    </head> <body>
      &lt;script&gt;
         var net = require('net');
         var client = net.connect({port: 8080}, function() {
            console.log('Connection established!');  
         });
         
         client.on('data', function(data) {
            document.write(data.toString());
            client.end();
         });
         
         client.on('end', function() { 
            console.log('Disconnected :(');
         });
      &lt;/script&gt;
    </body> </html>

    Run the server using the following command −

    $ node server.js
    

    Run the application using the following command −

    $ electron ./main.js
    

    The above command will generate the following output −

    Net Module

    Observe that we connect to the server automatically and automatically get disconnected too.

    We also have a few other node modules that we can be used directly on the front-end using Electron. The usage of these modules depends on the scenario you use them in.

  •  File Handling

    File handling is a very important part of building a desktop application. Almost all desktop apps interact with files.

    We will create a form in our app that will take as input, a Name and an Email address. This form will be saved to a file and a list will be created that will show this as output.

    Set up your main process using the following code in the main.js file −

    const {app, BrowserWindow} = require('electron')
    const url = require('url')
    const path = require('path')
    
    let win
    
    function createWindow() {
       win = new BrowserWindow({width: 800, height: 600})
       win.loadURL(url.format ({
    
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
    })) } app.on('ready', createWindow)

    Now open the index.html file and enter the following code in it −

    <!DOCTYPE html>
    <html>
       <head>
    
      &lt;meta charset = "UTF-8"&gt;
      &lt;title&gt;File System&lt;/title&gt;
      &lt;link rel = "stylesheet" 
         href = "./bower_components/bootstrap/dist/css/bootstrap.min.css" /&gt;
      
      &lt;style type = "text/css"&gt;
         #contact-list {
            height: 150px;
            overflow-y: auto;
         }
      &lt;/style&gt;
    </head> <body>
      &lt;div class = "container"&gt;
         &lt;h1&gt;Enter Names and Email addresses of your contacts&lt;/h1&gt;
         &lt;div class = "form-group"&gt;
            &lt;label for = "Name"&gt;Name&lt;/label&gt;
            &lt;input type = "text" name = "Name" value = "" id = "Name" 
               placeholder = "Name" class = "form-control" required&gt;
         &lt;/div&gt;
         
         &lt;div class = "form-group"&gt;
            &lt;label for = "Email"&gt;Email&lt;/label&gt;
            &lt;input type = "email" name = "Email" value = "" id = "Email" 
               placeholder = "Email" class = "form-control" required&gt;
         &lt;/div&gt;
         
         &lt;div class = "form-group"&gt;
            &lt;button class = "btn btn-primary" id = "add-to-list"&gt;Add to list!&lt;/button&gt;
         &lt;/div&gt;
         
         &lt;div id = "contact-list"&gt;
            &lt;table class = "table-striped" id = "contact-table"&gt;
               &lt;tr&gt;
                  &lt;th class = "col-xs-2"&gt;S. No.&lt;/th&gt;
                  &lt;th class = "col-xs-4"&gt;Name&lt;/th&gt;
                  &lt;th class = "col-xs-6"&gt;Email&lt;/th&gt;
               &lt;/tr&gt;
            &lt;/table&gt;
         &lt;/div&gt;
         
         &lt;script src = "./view.js" &gt;&lt;/script&gt;
      &lt;/div&gt;
    </body> </html>

    Now we need to handle the addition event. We will do this in our view.js file.

    We will create a function loadAndDisplayContacts() that will initially load contacts from the file. After creating the loadAndDisplayContacts() function, we will create a click handler on our add to list button. This will add the entry to both the file and the table.

    In your view.js file, enter the following code −

    let $ = require('jquery')
    let fs = require('fs')
    let filename = 'contacts'
    let sno = 0
    
    $('#add-to-list').on('click', () => {
       let name = $('#Name').val()
       let email = $('#Email').val()
    
       fs.appendFile('contacts', name + ',' + email + '\n')
    
       addEntry(name, email)
    })
    
    function addEntry(name, email) {
       if(name && email) {
    
      sno++
      let updateString = '&lt;tr&gt;&lt;td&gt;'+ sno + '&lt;/td&gt;&lt;td&gt;'+ name +'&lt;/td&gt;&lt;td&gt;' 
         + email +'&lt;/td&gt;&lt;/tr&gt;'
      $('#contact-table').append(updateString)
    } } function loadAndDisplayContacts() { //Check if file exists if(fs.existsSync(filename)) {
      let data = fs.readFileSync(filename, 'utf8').split('\n')
      
      data.forEach((contact, index) =&gt; {
         let &#91; name, email ] = contact.split(',')
         addEntry(name, email)
      })
    } else {
      console.log("File Doesn\'t Exist. Creating new file.")
      fs.writeFile(filename, '', (err) =&gt; {
         if(err)
            console.log(err)
      })
    } } loadAndDisplayContacts()

    Now run the application, using the following command −

    $ electron ./main.js
    

    Once you add some contacts to it, the application will look like −

    File

    For more fs module API calls, please refer to Node File System tutorial.

    Now we can handle files using Electron. We will look at how to call the save and open dialog boxes(native) for files in the dialogs chapter.

  •  Building UIs

    The User Interface of Electron apps is built using HTML, CSS and JS. So we can leverage all the available tools for front-end web development here as well. You can use the tools such as Angular, Backbone, React, Bootstrap, and Foundation, to build the apps.

    You can use Bower to manage these front-end dependencies. Install bower using −

    $ npm install -g bower
    

    Now you can get all the available JS and CSS frameworks, libraries, plugins, etc. using bower. For example, to get the latest stable version of bootstrap, enter the following command −

    $ bower install bootstrap
    

    This will download bootstrap in bower_components. Now you can reference this library in your HTML. Let us create a simple page using these libraries.

    Let us now install jquery using the npm command −

    $ npm install --save jquery
    

    Further, this will be required in our view.js file. We already have a main.js setup as follows −

    const {app, BrowserWindow} = require('electron')
    const url = require('url')
    const path = require('path')
    
    let win
    
    function createWindow() {
       win = new BrowserWindow({width: 800, height: 600})
       win.loadURL(url.format ({
    
      pathname: path.join(__dirname, 'index.html'),
      protocol: 'file:',
      slashes: true
    })) } app.on('ready', createWindow)

    Open your index.html file and enter the following code in it −

    <!DOCTYPE html>
    <html>
       <head>
    
      &lt;meta charset = "UTF-8"&gt;
      &lt;title&gt;Hello World!&lt;/title&gt;
      &lt;link rel = "stylesheet" 
         href = "./bower_components/bootstrap/dist/css/bootstrap.min.css" /&gt;
    </head> <body>
      &lt;div class = "container"&gt;
         &lt;h1&gt;This page is using Bootstrap and jQuery!&lt;/h1&gt;
         &lt;h3 id = "click-counter"&gt;&lt;/h3&gt;
         &lt;button class = "btn btn-success" id = "countbtn"&gt;Click here&lt;/button&gt;
         &lt;script src = "./view.js" &gt;&lt;/script&gt;
      &lt;/div&gt;
    </body> </html>

    Create view.js and enter the click counter logic in it −

    let $ = require('jquery')  // jQuery now loaded and assigned to $
    let count = 0
    $('#click-counter').text(count.toString())
    $('#countbtn').on('click', () => {
       count ++ 
       $('#click-counter').text(count)
    }) 

    Run the app using the following command −

    $ electron ./main.js
    

    The above command will generate the output as in the following screenshot −

    UI

    You can build your native app just like you build websites. If you do not want users to be restricted to an exact window size, you can leverage the responsive design and allow users to use your app in a flexible manner

  • How Electron Works

    Electron takes a main file defined in your package.json file and executes it. This main file creates application windows which contain rendered web pages and interaction with the native GUI (graphical user interface) of your Operating System.

    As you start an application using Electron, a main process is created. This main process is responsible for interacting with the native GUI of the Operating System. It creates the GUI of your application.

    Just starting the main process does not give the users of your application any application window. These are created by the main process in the main file by using the BrowserWindow module. Each browser window then runs its own renderer process. The renderer process takes an HTML file which references the usual CSS files, JavaScript files, images, etc. and renders it in the window.

    The main process can access the native GUI through modules available directly in Electron. The desktop application can access all Node modules like the file system module for handling files, request to make HTTP calls, etc.

    Difference between Main and Renderer processes

    The main process creates web pages by creating the BrowserWindow instances. Each BrowserWindow instance runs the web page in its own renderer process. When a BrowserWindow instance is destroyed, the corresponding renderer process is also terminated.

    The main process manages all web pages and their corresponding renderer processes. Each renderer process is isolated and only cares about the web page running in it.