What have we done
- Installed and configured the code editor.
- We created a working folder and added our project files there.
- Learned how to edit and save code files.
- We installed the extension to immediately see the result of the layout.
In the following parts, we will talk about adding and checking JavaScript code, and how to make working with the code even more convenient. Subscribe to our newsletter so you don't miss the next issues.
Don't know what code to write?
Learn about HTML and CSS in interactive courses - free of charge.
Registration
Clicking the button - consent to the processing of personal data
Why might a browser not be enough?
Similar approaches and their disadvantages
At the moment, there are several different technologies for creating desktop applications based on web technologies. Here is a partial list of them:
- Adobe flash
- Tide SDK (ex. Titanium Desktop)
- App.js
- Brackets Shell
- Tint
- And others…
In my subjective opinion, the main disadvantage of these technologies is that the average web developer will have to suffer a lot, mastering all the intricacies of the API and the internal philosophy of any of them. You will need to sift through tons of documentation and examples just to start doing something and see the first result.
With nw.js everything is much simpler. If you develop web applications and have some experience with node.js, then within a few hours you will understand how to write and build desktop applications for mac, windows and linux.
From node-webkit to nw.js. A little history
In 2011, Chinese developer Roger Wang founded the node-webkit project, the main idea of which was to use web technologies to write full-featured cross-platform desktop applications. As the name suggests, the main components of the project are Node.js and Webkit (Chromium).
Years passed and in April 2013 Chromium, and with it the node-webkit project moved to the new Blink engine (a fork of Webkit). In addition to this, since January 2020 the project began using io.js instead of node.js.
As a result, the original name “node-webkit” became completely irrelevant and it was decided to rename the project to nw.js. There is an opinion that now the letters NW have a new meaning - “Native Web”.
The main sponsors of the project are still Intel and Gnor Tech.
Main idea. Why “cross” Chromium with node.js?
When we talk about desktop applications, we imagine a kind of graphical interface, interacting with which we make changes at the system level of the operating system (for example, copy files, launch processes, execute system commands, etc.)
In order to understand the power of the nw.js idea, let's take a quick look at the main components of nwjs.
Chromium is an open source browser developed by Google, Opera Software, Yandex, NVIDIA and other companies. Chromium uses Blink (a fork of Webkit) as the engine for displaying web pages. V8 is used as the JavaScript processing engine.
node.js(io.js) is a JavaScript runtime based on the v8 engine originally used in Chromium. It is written in C++ and operates at the application layer protocol level, where many different operating system APIs are available to it, such as the file system and network communications. Because of this, node is most often used to build system applications and servers.
The main idea of nw.js is to combine Chromium and node.js into a single context, using the same v8. To be more precise, node.js uses v8 Chromium. Those. With Chromium we can create a GUI based on html, css, js, just like in any web browser. But, unlike a regular browser, nw.js allows you to call node.js functions from the same context to work with the system APIs of the operating system.
Let's look at a simple example. Using the fs module for io.js, we will monitor changes to a file in the system. If the file has changed, we will display its contents in a div-e with id=”log”.
js
var fs = require('fs');
var path = '/usr/local/var/log/nginx/error.log'; fs.watchFile(path, function(a){ document.getElementById('log').innerHTML = fs.readFileSync(path, {encoding:'utf8′}); }); As we can see, there is no server and client, no ajax, no sockets, no http, no data exchange over the network. As we said, the beauty of nwjs lies in the ability to work with node.js from the Chromium context.
How did they do it
The nw.js developers have put a lot of effort into providing a single event loop and building a “bridge” between the node.js and chromium contexts. Here you can read more about the technical details and problems that arose during the implementation of this idea.
Operating system interface elements.
Nw.js allows you to create and manage operating system interface elements typical for desktop applications (window menu, tray, context menus). You can also access the clipboard, system key combinations, etc.
To do this, you just need to connect the nw.gui module, which is already included in the standard package. It makes it possible to abstract from the implementation of interface elements in a specific operating system by providing a common API.
var gui = require('nw.gui'); gui.Window.get(); //window gui.Shell(); // shell gui.Tray // tray gui.Menu // menus gui.Clipboard // clipboard gui.Shortcut // keyboard shortcuts // ...and other elements
Now let's take a closer look at some of the features described above.
Creating system context menus
js
// Create an empty menu var menu = new gui.Menu();
// Add items or separators to it menu.append(new gui.MenuItem({ label: 'Do nothing' })); menu.append(new gui.MenuItem({ type: 'separator' })); // .. and attach handlers to them menu.append(new gui.MenuItem({ label: 'Say "Hello!"', click: function() { alert('Hello!') } })); // Show as a context menu document.body.addEventListener('contextmenu', function(e) { e.preventDefault(); // In the place where we clicked menu.popup(ex, ey); return false; } , false); This is what we get as a result when we right-click on the window:
Creating a Window Menu
js
// Create a top menu var menubar = new gui.Menu({ type: 'menubar', title: 'Menu Title' });
// For nested menus we use the same code as in the example with the context menu. menubar.append(new gui.MenuItem({ label: 'Main', submenu: menu})); menubar.append(new gui.MenuItem({ label: 'About us', submenu: menu})); //Get the current window and connect the top menu to it gui.Window.get().menu = menubar; Result:
Creating icons and menus in the tray (menubar)
js
// Create an icon in the tray (menubar) var tray = new gui.Tray({ title: 'ololo', icon: 'icon.png', alticon: 'icon.png' });
// Add a menu when you click on the tray icon var traymenu = new gui.Menu(); traymenu.append(new gui.MenuItem({label: 'That', type: 'checkbox'})); traymenu.append(new gui.MenuItem({label: 'This', type: 'checkbox' })); traymenu.append(new gui.MenuItem({label: 'Other', type: 'checkbox'})); traymenu.append(new gui.MenuItem({type: 'separator' })); // For nested menus we use the same code as in the example with the context menu. traymenu.append(new gui.MenuItem({label: 'or ...', submenu: menu})); tray.menu = traymenu; Result:
Handling keyboard shortcuts
js
var shortcut = new gui.Shortcut({ key : "Ctrl+Shift+L", active : function() { console.log('Key combination pressed', this.key) }, failed : function(msg) { // it is impossible to register this keyboard shortcut // it may already be taken console.log(msg); } }); // register the keyboard shortcut in the system gui.App.registerGlobalHotKey(shortcut); // unsubscribe from the keyboard shortcut in the system gui.App.unregisterGlobalHotKey(shortcut);
Working with the clipboard
js
var clipboard = gui.Clipboard.get(); // get the value var text = clipboard.get('text'); // set the value clipboard.set('Hello', 'text'); // clear the buffer clipboard.clear();
Let's start the dive
To get started, download and install the latest version of nw.js for your platform. Next, follow the documentation instructions to configure the command line and aliases for your operating system.
nw.js application structure
An application for nw.js consists of regular html, css, js files, structured in any way. There are no additional rules or conventions for their layout.
When nw.js starts, it looks for a package.json manifest file.
Example package.json
{ "main": "index.html", "name": "dummydemo", "description": "Dummy demo of nnwjs app", "version": "0.0.1", "keywords": [ "demo", "nwjs" ], "window": { "title": "Dummy demo", "icon": "icon.png", "toolbar": false, "frame": true, "width": 700, "height" : 400, "position": "mouse", "min_width": 400, "min_height": 200, "max_width": 800, "max_height": 600 }, "author": "nedudi", "license": "MIT ", "dependencies": { "moment": "latest", "handlebars": "^2.0.0" } }
This file is no different from the regular package.json in node.js, except that it contains additional parameters: window, user-agent, chromium-args, js-flags and others. They allow nw.js to configure and control the behavior of Chromium and its environment, add flags when running node.js, change the display mode, window sizes, icons, application entry point and many other settings.
For example, we'll create an index.html file and add some CSS.
index.html
Hello NW.JS!
Then open the console and type:
$ nw my/lovely/app
where my/lovely/app is the path to the application folder, and nw is a correctly configured alias for nw.js
That's all! This will launch a desktop application that looks something like this:
Window display settings
The result we see is very similar to a regular browser with an address bar. Basically, this is a browser! Yes, yes, the same Chromium we were talking about.
However, in most cases, we want our creation not to look like a browser, but more like a familiar desktop application.
There are a number of settings available in package.json for this. Let's take a closer look at some of them.
First, we can remove the toolbar .
package.json
... "window": { "toolbar": false } ...
You can optionally hide the window frame .
package.json
... "window": { "toolbar": false, "frame": false } ...
Or remove the window background altogether , leaving only the content .
package.json
... "window": { "toolbar": false, "frame": false, "transparent": true } ...
Kiosk-mode
Another powerful option is the ability to run applications in Kiosk-mode. This mode is often used in desktop games, as well as on screens in public places (for example, to display advertising on large monitors). Exiting an application running in Kiosk-mode is not as easy as exiting a browser-based fullscreen. This can only be done using the nw.js, Alt-Tab or Ctrl-Alt-Del (Windows) API methods, therefore, when developing applications that work in this mode, you yourself must take care of the presence of some “Exit” button in the interface, which will help the user close it.
package.json
... "window": { "kiosk": true } ...
And finally, we can simply hide the window , leaving the application in the background
"window": { "show": false }
Building applications using nw.js
A detailed manual for assembling applications for different platforms is here. But, to be honest, I wouldn’t recommend reading it when writing your own application for the first time. You will need it when working with specific solutions and approaches.
In standard cases, it is better to use the ready-made node-webkit-builder plugin.
All you need to do is install node-webkit-builder and run the nwbuild command with the path to your application folder.
$ npm i -g node-webkit-builder $ nwbuild ./
If you need to build an application for specific operating systems, you can specify a list of them using the -p flag
$ nwbuild ./ -p win32,win64,osx32,osx64,linux32,linux64
In this case, nwbuild itself will download the latest versions of nw.js and make assemblies for all specified platforms (each in a separate folder).
This is what I got after opening the assembled test application in various OSes: