Web apps can be desktop apps if you bundle the web server

(written by lawrence krubner, however indented passages are often quotes). You can contact lawrence at: lawrence@krubner.com, or follow me on Twitter.

It’s an interesting idea, a sort of uberjar idea, in the sense that you bundle all dependencies as one app. You can bundle up all the pieces of a web app and make it a desktop app by including the webserver. Indeed, I do exactly that every time I run “lein uberjar” on one of my Clojure apps (when I embed the Jetty server with my app):

Node is a lightweight JavaScript runtime based on the Google Chrome V8 engine. Node is written in C++ and lives in the operating-system application layer where it supports a lot of OS APIs such as file system and network operations therefore it can be used to build system and server-side apps.

WebKit is a web browser engine. Let’s take a web page as an example: it’s built with HTML, CSS and JavaScript. After the page is loaded, it will be parsed into a tree and handed off to WebKit for rendering hence forming the page we see in a browser. Node-webkit is based on Blink, which is a rendering engine forked from WebKit and whose JavsScript engine is V8, which is also used in Node.

The browser security model prevents WebKit from issuing system calls, which is a must-have for desktop applications; since Node itself has system-level APIs but lacks rendering support, Roger had the idea in 2011 to create node-webkit, combining system-level operations and user interactions. After some trials with WebKitGTK and Node, he started using Chromium in 2012, basing the project entirely on Chromium from the initial Chromium Embedded Framework (CEF).

Following the fast development of Node and Chromium, node-webkit is at version 0.10 today. We’ll dive into the details of how node-webkit works.

Node is an event-driven framework with message processing based on libuv. The JS engine of WebKit is based on MessagePump of Chrome, which is also event-driven. Event-driven can be explained as when an event happens, for example, user input comes in, the corresponding code is executed to process the event. Node-webkit combines the event-processing of Node and WebKit into a single message loop.

We still have another challenge after combining event processing: we need to find a way for Node and WebKit to access the context of each other. There are two contexts in node-webkit: the Node context and the WebKit context. Accessing the context of each other means accessing the objects of each other, so during the initialization of node-webkit, the Node context will be injected into WebKit so that the WebKit context will have access to the Node context.

Node-webkit has made changes to the security model of WebKit as well. In node-webkit, there are two kinds of frames: Node frames and normal frames1. If you’re familiar with Web development, you probably know that issuing a cross-domain AJAX request will result in errors imposed by same-origin policy. The same restriction is imposed on normal frames of node-webkit as in a browser. However, there is no such restriction on Node frames: the same security token is shared in all Node frames, including the Node’s context and the WebKit’s Context, and cross-domain access are allowed and objects in the Node’s context are accessible too. Therefore, app developers must take precaution with untrusted user input to prevent destructive actions or put them into a normal frame.

Chromium Layers Chromium Conceptual Application Layers
It is worth noting that even though Chrome supports HTML5 pretty well, some features are implemented on the Browser layer (see the graph above) and the WebKit in node-webkit inherits up to the Contents layer (i.e. the WebContents layer on the above image) as node-webkit itself is the implementation of the Browser layer. Therefore, some HTML5 features such as Web Notification2 are not supported in node-webkit. Nevertheless, the Chromium team is moving these HTML5 features onto the Content layer, which is definitely good news for node-webkit.

If you look at the above graph carefully, you will find there is also UI rendering in the Browser layer. Node-webkit implements UI rendering in the same way: it has native UI component APIs such as Menu, System Tray, Clipboard etc. The implementation is inspired from the cross-platform UI of Chromium.

Post external references

  1. 1