0

Creating a cross-platform stand-alone applications on Node.js [part 2]

Creating a cross-platform stand-alone applications on Node.js [part 2]

Introduction

In my previous article I talked about how to start the development of desktop applications based on web technologies. Now I would like to continue the topic, to demonstrate that the development under the desktop is ever more was not as nice and easy as it is now using the Electron.

Github Electron

Whenever it comes to the study of a new product, the main source of information and examples - it is official documentation Electron API. Keep an open tab to refer to it for study opportunities of Electron

In order to create a complete application on the basis of the test case, we will use the following components of framework:

Basics

The application as such is divided into 2 different processes

  1. The main process in which the processing of all business logic of applications, the interaction between all components of NodeJs
  2. Browser process, in which the content and processing of all other interactions frontend

Windows of an application

To create a new window, whether modal or normal, you need to get a new instance of the object BrowserWindow. The browser window interacts with the application process through the built communicator ipcRenderer, and to interact with the application process, the browser process used ipcMain communicator.

The browser can load both local html pages and web sites with any functionality that is available in the browser.

// In the main process.
const {BrowserWindow} = require('electron')

// Or use `remote` from the renderer process.
// const {BrowserWindow} = require('electron').remote

let win = new BrowserWindow({width: 800, height: 600})
win.on('closed', () => {
  win = null
})

// Load a remote URL
win.loadURL('https://github.com')

// Or load a local HTML file
win.loadURL(`file://${__dirname}/app/index.html`)

The browser window has a number of events that you want to use to properly download content and process behavior on the page

  • ready-to-show
  • page-title-updated
  • close, closed
  • blur, focus, show, hide
  • responsive, unresponsive
  • maximize, unmaximize, minimize
  • restore, resize, move
  • moved
  • enter-full-screen, leave-full-screen, enter-html-full-screen, leave-html-full-screen
  • app-command

There are also several optional events that work only on MacOS

  • scroll-touch-begin
  • scroll-touch-end
  • scroll-touch-edge
  • swipe

As you can see, to work with an object given a sufficient number of events, properties and functions. It allows you to create complete windows of an application

System tray

As a rule, a good application is recommended to have a system tray menu, the user has quick access to useful functions without entering the main application window. To gain access to an object that works with the system tray, you need to get it out of the application object.

A very clear example of how to quickly integrate and see firsthand, you can browse the code block:

const {app, Menu, Tray} = require('electron')

let tray = null
app.on('ready', () => {
  tray = new Tray('/path/to/my/icon')
  const contextMenu = Menu.buildFromTemplate([
    {label: 'Item1', type: 'radio'},
    {label: 'Item2', type: 'radio'},
    {label: 'Item3', type: 'radio', checked: true},
    {label: 'Item4', type: 'radio'}
  ])
  tray.setToolTip('This is my application.')
  tray.setContextMenu(contextMenu)
})

And that's enough. Easily. You can set an icon, to identify the menu list and their behavior, add tooltip when the mouse cursor is over the icon.

Menu

It's amazing how easy it is to set up your own application menu. It only takes a few minutes and a few lines of code. This is not C ++, here it is done in a jiffy, take a look:

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

const template = [
  {
    label: 'Edit',
    submenu: [
      {
        role: 'undo'
      },
      {
        role: 'redo'
      },
      {
        type: 'separator'
      },
      {
        role: 'cut'
      },
      {
        role: 'copy'
      },
      {
        role: 'paste'
      },
      {
        role: 'pasteandmatchstyle'
      },
      {
        role: 'delete'
      },
      {
        role: 'selectall'
      }
    ]
  },
  {
    label: 'View',
    submenu: [
      {
        role: 'reload'
      },
      {
        role: 'toggledevtools'
      },
      {
        type: 'separator'
      },
      {
        role: 'resetzoom'
      },
      {
        role: 'zoomin'
      },
      {
        role: 'zoomout'
      },
      {
        type: 'separator'
      },
      {
        role: 'togglefullscreen'
      }
    ]
  },
  {
    role: 'window',
    submenu: [
      {
        role: 'minimize'
      },
      {
        role: 'close'
      }
    ]
  },
  {
    role: 'help',
    submenu: [
      {
        label: 'Learn More',
        click () { require('electron').shell.openExternal('http://electron.atom.io') }
      }
    ]
  }
]

if (process.platform === 'darwin') {
  template.unshift({
    label: app.getName(),
    submenu: [
      {
        role: 'about'
      },
      {
        type: 'separator'
      },
      {
        role: 'services',
        submenu: []
      },
      {
        type: 'separator'
      },
      {
        role: 'hide'
      },
      {
        role: 'hideothers'
      },
      {
        role: 'unhide'
      },
      {
        type: 'separator'
      },
      {
        role: 'quit'
      }
    ]
  })
  // Edit menu.
  template[1].submenu.push(
    {
      type: 'separator'
    },
    {
      label: 'Speech',
      submenu: [
        {
          role: 'startspeaking'
        },
        {
          role: 'stopspeaking'
        }
      ]
    }
  )
  // Window menu.
  template[3].submenu = [
    {
      label: 'Close',
      accelerator: 'CmdOrCtrl+W',
      role: 'close'
    },
    {
      label: 'Minimize',
      accelerator: 'CmdOrCtrl+M',
      role: 'minimize'
    },
    {
      label: 'Zoom',
      role: 'zoom'
    },
    {
      type: 'separator'
    },
    {
      label: 'Bring All to Front',
      role: 'front'
    }
  ]
}

const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)

In the example above we have created a menu item and appointed him as the application menu using the method Menu.setApplicationMenu (menu). You can create shortcuts to invoke commands using combinations of universal names for both Windows and for MacOS, like CmdOrCtrl and so on. The menu also can be built with the help of a special class of MenuItem, which offers more flexibility to configure the behavior of events and functions of the menu item.

Debugging applications

During the development process you often need to debug the application, fix the errors and carry out any inspection of the code. The Chromium integrated Developer Tools that will work with the code in runtime, it will allow you to debug the same way as if you were doing it in the usual browser.

In order to open the developer tools is enough to select the item at the top of the application menu bar or press the shortcut key Ctrl + Shift + i

Auto-updates

One interesting feature of this framework is the presence of built-in capabilities to perform automatic updates. I was able to expand effortlessly electron-release-server, is the server to download updates that supports releases for different operating systems. The server can be deployed in minutes and set up a production environment for one to two hours. You can find it in the repository GitHub

Security of code

In order to secure the commercial code of the application is recommended to write the native module to compile NodeJs on any language, such as C++, Go, C#. Next to this module can be used a variety of obfuscation, cryptography, and other protection to the attacker had not been able explore the code of your application and change its bytecode.

Since we are in the application engine NodeJS, then we can easily connect it to the native modules and to implement our application API calls from JS to this compiled module. Methods of creating tamper-proof compiled code can be found in sufficient quantities on the Internet.

Conclusion

Of course, that this framework is not limited. He has a lot of features to work with http requests, to obtain information about the system, work with files, clipboard, and more.

Try it and you will understand that to create applications on this framework, a pleasure not only from the simplicity and speed, but also opens up new possibilities for the realization of all your ideas

Creating a cross-platform stand-alone applications on Node.js [part 1]


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.