Build Desktop Apps with JavaScript and Node WebKit

by Ben Farrell on February 10, 2014

The modern web is always changing, and this article is more than two years old.

By Ben Farrell

I’m a big fan of platforms that enable me to experiment and do creative things. As someone who was big into Flash and tends to do mostly HTML/JS/CSS now, the main problem with both of these is that they are limited by the capability of the browser. If the browser allowed me to do everything I wanted, we’d have a lot of unhappy and insecure browser users. I’m talking about things like access to the user’s file system, running random bits of C++, et cetera. Basically, lots of the ideas I have that would be super cool to do are also things that malicious developers would love to do to compromise your machine.

While current browsers are occasionally limiting, the languages and underlying tech we use in browsers are not. There is a long history of various wrappers that take a web app and give it extra capability as a desktop application. These wrappers will often remove many of the restrictions imposed by browsers and allow us to do virtually anything we as developers might want to do.

What if we could approach the problem from a different angle? What if we took an existing, non-visual platform that already allows developers to do whatever they want and put a visual layer on top of it? That platform is Node.js and that visual layer is WebKit. Put them together, with Javascript as the underlying engine and WebKit as the visual layer, and you have Node-WebKit!

Node-WebKit is created and developed in the Intel Open Technology Center. It has a couple years’ worth of maturity under its belt as well. In this post I’ll show you how to get started with Node-Webkit and even build your first application.

Why Node.js?

Maybe you like Ruby, Python, or another awesome language that offers the capabilities that I’m talking about. These platforms are great (I’ve done some Python and love it), but Node.js offers us something that the others don’t have: Javascript.

Javascript is, of course, common to working with Node.js and WebKit, and that is its biggest positive in this case. We can write Javascript for Node.js or WebKit with little regard for where Node ends and the visual layer begins. We can mix in Node.js specific file-system calls in the middle of our jQuery UI component or AngularJS directive.

Application development feels extremely cohesive with Node WebKit. Additionally, because Javascript is the most popular language today due to its ubiquitous web presence, we have a massive number of UI toolkits and frameworks to choose from.

Getting Started

Over the past year, working with Node WebKit has become much easier because of tools like Yeoman. You can visit the Node-WebKit GitHub repo and read up on how to start building a new project, or you can simply use Yeoman to crank out a nice Node-WebKit starter project for you.

Before you start though, there are a few prerequisites:

  • Install Node.js (of course)
  • Install Yeoman globally: npm install –g yeoman
  • Install the Yeoman Node WebKit Generator globally: npm install –g generator-node-webkit
  • Install Node WebKit globally: npm install –g nodewebkit
  • Install the Grunt CLI globally: npm install –g grunt-cli

With all of this setup, go ahead and create your project directory. I’ve called mine “nwkit-example.” Go into that directory via the command line and enter the command: yo node-webkit. As you can see, you’ll be asked a few questions as Yeoman goes through and sets up your application. Be prepared to wait a little at the end – the WebKit downloads take a minute or two to come in.

Running the Yeoman generator for Node Webkit

Running the Yeoman generator for Node Webkit

After running the generator, you can see that an entire sample project is set up and ready to go. I’ve loaded the project into my favorite IDE, WebStorm. Of course, your favorite IDE or text editor will work just fine as well.

The files and folders generated by Yeoman

The files and folders generated by Yeoman

With a working project set up, you’ll want to run it. There are two ways to go about this. Either package up your application in an executable or run your Web files (inside the”app” folder) against the Node Webkit executable. Obviously, since you’ll be constantly editing and tweaking files, you’ll want the quickest and easiest method, so choose the latter.

These executables live inside “resources/node-webkit/{your-platform}”. On Windows, for example, you could open nw.exe via the command line with the arguments pointing to your app folder. There is an easier way – and that’s why we installed Node WebKit globally before.

From the command line in your project root, type nodewebkit app. This will run your app folder (with all of your HTML/JS/CSS files) against the globally installed Node Webkit, giving you your application window.

Running the Yeoman generated desktop app.

Running the Yeoman generated desktop app.

I won’t even get into the obvious step here of doing a “Hello, World”. You can see from the screenshot that the default HTML entry point is in app/views/index.html. If you wanted to add some text to this view, go ahead and try – you’re all familiar with adding text to an HTML page, right?

Speaking of the tool/address bar, how do you hide it? I’ll tell you, but before you do, realize that it’s fantastic for debugging your application, so don’t be too hasty. In addition to the address bar, the menu button on the right offers the same developer tools you’d expect from Chrome or Safari. Therefore, I’d suggest only hiding these items when you want to put the finishing touches on your project.

In order to hide the toolbar, you’ll need to edit the the app/package.json file. This file controls a bunch of different options you can set for how the application is wrapped. You’ll see window size, minimum window size, title, and more. What you won’t see is a toolbar: false argument in the window object. If you add this, your toolbar will disappear.

Tweak it and look at the output.

The generated app running without the address bar.

The generated app running without the address bar.

Lastly, let’s take a look at how to package an application. As a prerequisite, you installed the task-runner Grunt. If you do web development, it wouldn’t be shocking for you to have already had this installed. I’ve got to hand it to the folks that made this Yeoman Generator—having a Grunt task to do various things with Node WebKit is very handy!

If you’re on Windows right now, choose the task “dist-win” (as opposed to “dist-mac” or “dist-linux”). From the root of your project, type:

grunt dist-win

Here’s what you get:

Running the task to package our desktop app.

Running the task to package our desktop app.

 

The files within the distribution package on Windows.

The files within the distribution package on Windows.

I’ve expanded the zip output so you can see some of the files. There are a couple of interesting things here in the .dll files (or probably .so files if you’re on Linux or OSX). For example, FFMPEG is a well-known library for doing video encoding and decoding, and libGLE handles OpenGL. These libraries handle HTML5 video and WebGL respectively. So it’s nice to know that those HTML5 features are still there when working on a desktop application.

Now that you are up and running for building some basic desktop application goodness driven by Node-WebKit, let’s look at building a better example.

An Example Application

Let’s move beyond the “Hello, World” application – or rather your blank application created above- and get into some of the real capabilities that you can’t get in your browser or Node.js alone.

At the start of this article, I was getting excited about the possibilities for combining my favorite tools and libraries in the browser with the power of Node.js. Currently, AngularJS and Angular Bootstrap are my favorite ways to start an application – and they work perfectly here (again, yay, WebKit!). But, what to build?

Lately I’ve been working on a mobile game of sorts using Cordova/Phonegap. I’ve been needing a way to get console.log output from my mobile device onto my desktop machine so that I could debug what’s going on. I’d looked into Weinre, and it’s a great project, but I have to set things up every time I sit down to debug. Easy things, too, like making sure my mobile device is on the same wifi network, looking up the IP address and adding it to my mobile app, and starting up the Node.js-based Weinre server. It’s not that difficult, but I preferred using ADB since I’m focusing on Android right now. ADB creates a bridge, typically over USB, between the device and the Android SDK, provided there is an ADB server on the machine.

If you open a command line prompt and type in adb logcat, you’ll see a massive number of log messages from your device. I thought it would be nice to create a UI wherein you could see, filter, and format the incoming messages. I don’t care about 99.9% of the Android logs that come in, I just want to see the ones that come from a Javascript console.log.

I’ve briefly looked up other ways to do that and couldn’t come up with anything. The ADB server Chrome App looked promising, but here’s what I see when I go to the Chrome store:

Trying to install the ADB Server Chrome app.

Trying to install the ADB Server Chrome app.

Oh well, why not see what we can do with Node-WebKit!

ADBKit

Did I mention I love the Javascript/Node.js community? Well, I do. Anything you could possibly want to do seems like it’s been done, and you can find it on npmjs.org. To interact with ADB in Node.js, I found ADBKit. It’s described as “a pure Node.js client for the Android debug bridge”.

Using ADBKit, I started the ADB server (assuming the Android SDK is installed) to get a list of my connected devices and finally open up a connection to logcat for a specific device. Even better, ADBKit provides a nice little listener to notify me when each and every log entry comes in.

Pretty powerful and nice for a Node.js library, but what about the visual layer? Getting this far requires some basic knowledge of using Node.js and npm to get ADBKit installed and start using it. Going even farther into the WebKit side of the project involves some AngularJS skills. I won’t bore you with that, but I will share a Gist to prove a powerful point about Node WebKit.

https://gist.github.com/bengfarrell/8777742

In the Gist, I’ve included what’s called a “service” in AngularJS. It’s pretty commonplace stuff in Angular,  sort of like a Singleton that provides me with features anywhere across my application. Within the code, I’ve indicated a couple places where I’ve sprinkled in some Node.js to show how it interacts with ADBKit. The fact that I had to point out where this code is means there really is no dividing line in my application between Node and WebKit. Placing stuff that would only work through Node.js inside an Angular construct is crazy if you think about it. Here I have a framework (Angular) that’s designed to run in a browser, but I’m running it in on a desktop application while simultaneously running code that would only run on a Web server. At the least, I might expect to need some crazy workarounds, but no, it runs flawlessly.

The Android Whisperer

So in the end, I have a project I’ve dubbed “The Android Whisperer” built over a couple nights with Node.js, Node-WebKit, Angular, and Bootstrap. It’s definitely not perfect. It crashes when I press the button to start the ADB Server, but once I kick it off again, I’m rolling in log messages from my favorite Android device.

Log output unfiltered.

Log output unfiltered.

And then if I change the filter to “jsconsole”, I can see my Javascript console.log output:

Log output filtered to jsconsole.

Log output filtered to jsconsole.

That’s extremely useful because I’m trying to log things that use my mobile device’s accelerometer, compass, and gyroscope that I just can’t test on my laptop.

The other cool thing about this project is that I don’t have to show log messages. I could make an HTML5-based app or Website that uses console.log events to trigger events over ADB. You’ve seen mobile devices being used as joysticks or controllers for big screens. Those typically function over Websockets. With ADBKit and Node WebKit, we can plug right in! Maybe using ADB isn’t better than Websockets, but it certainly provides one more option.

Even More Possibilities

Obviously you can go beyond Android logging with Node Webkit. The possibilities are endless, and there are countless Node plugins at npmjs.org. The prospect of putting a front-end on any of them is just awesome. The flavor of front-end is unlimited when smart folks in the Web community seem to be putting out new frameworks and tools every day.

I’ve actually published a plugin through NPM called NuiMotion that allows you to track a user’s skeleton with a 3D-sensing camera like the Kinect. That was an interesting project because it was my first attempt at wrapping an existing C++ library for use in Node.js. That plugin is relevant to this discussion because not every Node.js plugin works right out of the box in Node WebKit. ADBKit, as you’ve seen, works great because it’s written in pure Javascript. My plugin, and others like it, require a compilation step to go from C++ to .node file. The process to make one is pretty easy, and it happens all the time when dealing with Node.js. When using an npm install, the plugin is downloaded but it also might need a build step to compile for the platform. That compilation is done using something called “node-gyp”.

But node-gyp doesn’t work with Node WebKit. Instead, the creators of Node WebKit have given us a tool called “nw-gyp”. It runs the same exact way, just swaps in “nw” for “node” in the command prompt. Just know that if you wade deep into these waters, you may have to compile a plugin here or there with this new utility.

Even with that extra step, I’d say that Node WebKit can do pretty much anything. Check out these applications and companies that use Node.js + WebKit to make things that couldn’t have been done with either one alone.

I hope you’re all inspired to do some cool things with Node WebKit. Use it with your favorite Javascript library. I recommend AngularJS, but you don’t have to listen to me. Use whatever you like!

18 comments"

  1. In the instructions you mention to npm install node-webkit. I believe you mean nodewebkit.

    1. Jean-David says:

      Yes, exactly, I had to search npm to figure it was nodewebkit.
      (It’s in the getting started list).

      Thanks for this article !

    2. Ben Farrell says:

      Oops! Thanks for the correction – the Yeoman Generator has the dash, I must have had that in mind when I wrote it

  2. LUIS says:

    the node-webkit or nodewebkit is not on the npm registry…
    the generator-node-webkit, or generator-nodewebkit or the generatornodewebkit is not In the NPM registry…

    unless I am typing this wrong, these components are unloadable…

    any ideas???

    Thanks Luis…

    1. remotesynth says:

      It should be “nodewebkit” as you can see at this url: https://www.npmjs.org/package/nodewebkit. I’ll make the change to the article text.

  3. Stefan says:

    Thanks for the great tutorial. I even managed to get a “Hello World”-App up and running.
    Fantastic.
    I would also like to include angularjs (in which I’m also a newbie) but already fail to include javascript files in the index.html
    Do you mind writing a step-by-step tutorial how you included angularjs and bootstrap into that “desktop-app”-structure?
    That would be awesome.
    Or is your example-project accessible somewhere?

  4. Stefan says:

    Bam … shame on me … I found you project on github and you even linked to it … sorry.

  5. I’m looking to create a repo for a NW project. After initial installation I have a tmp and a resources directory. Do either (both?) of those need to be checked into the repository or can they be .gitignored?

    1. Okay. The demo project you linked to, the Android Whisperer (https://github.com/bengfarrell/theandroidwhisperer), has both the resources and tmp directories included in it. I just need to know if those are required. I’m mostly thinking from a code sharing perspective. What is required for a coworker to check out this repo, work on it, then be able to build the apps.

  6. Ben Farrell says:

    So, I would definitely say that checking in the tmp directory to source control was a mistake on my part. Both of those directories (resources and tmp) only exist as part of the Grunt task that the Yeoman generator added.

    The resources directory is definitely important, as it contains the stuff needed to build a distribution on your platform. If I was working on a source controlled project with people, you’re right, I’d probably gitignore it. I’m not one to check binaries into source control. It only exists here as a place to copy resources from and put them into the distribution. And even then, it’s the structure that Yeoman/Grunt has in place to perform builds – it really doesn’t come from anything imposed by Node Webkit.

    If I was working on a project, I might keep these pre-built binaries in a safe place on my machine and have Grunt pull them in from there (or just gitignore this resources folder like you say). The pre-built binaries in the resources folder are just the downloads that come from https://github.com/rogerwang/node-webkit.

    For testing and whatnot, if you were going to do what I suggested and install Node Webkit globally, you wouldn’t even need these folders. It’s just to create the end executable.

    So, in regards to code-sharing: tmp and resources folders are not necessary

  7. Hey Ben, I’m finally ready with me app and I’m ready to package it up to show coworkers but I’m having trouble. I posted to the Google Group, but I wondered if you could also take a look:

    https://groups.google.com/forum/#!topic/node-webkit/mWm5OpkP6i0

  8. ackzell says:

    Thanks for the post. I was wondering how to add coffeescript support (and for that matter stylus and jade) while I’m developing. I know that the documentation about node-webkit says you can add it via loading the script on the webpage, but I was trying to implement it the node way (with require() ) . Although I am not quite sure where exactly it is I have to install the modules so that they can be loaded properly. I have tried installing nodewebkit (the npm package) locally and then installing coffeescript into it but to no avail. Also tried installing coffeescript directly into the folder where I used yeoman to create the project. I am feeling kind of lost now. Would you mind sharing an insight about this? Thank you again!

    1. Ben Farrell says:

      Hey ackzell,
      I haven’t actually done anything with CoffeeScript, but it is a language you would need to compile to JS. So, my best guess is to write Coffeescript and add something like a Grunt task to your project to compile your code. Your final application would then use the compiled JS instead of the source JS when running. Similar with Stylus and Jade.

      I’m sure there’s also some sort of live building of Coffeescript as well. There are most likely solutions that live as an Express.js application that compile your Coffeescript source before pulling it down into your application. This would probably be tricky to orchestrate since it’s usually behind a webserver and you’d like it to happen live in your desktop application.

      I digress though – I haven’t used any of these tools. However, my typical workflow for any HTML/CSS/JS preprocessing happens prior to deploying an application through a Grunt task. Once my application is created in some sort of build/distribution folder, I’d then deploy. You can use a watcher to compile on save for dev purposes.

      Either way, I’m not sure I see much need to do this stuff live in a desktop application – but you might have some good reasons!

      1. ackzell says:

        Thanks for your response. Indeed I was trying to add it to the development process. I just thought I could develop (since these tools aim to help you develop faster) and build “on the fly” so I could test the app right away. I’m trying to define a workflow for myself while I’m learning all these technologies and I’m tinkering with some ideas. Just to let you know… I was able to add coffeescript support just like the documentation for node-webkit says (installing coffeescript locally so that coffee-script is added to the node_modules folder and requiring it as a node module but the tricky part was adding “/register” to the end of the string parameter, thus: require(‘coffeescript/register”) made the trick).

  9. mcneela86 says:

    Hi, I am trying to repurpose an old .exe I made using TideSDK a couple years ago. I have replaced the relevent TideSDK code with node-webkit code, and everything seems to be working as expected. With one exception, the original (TideSDK .exe) used multiple html pages with simple anchor tags to change the view. When I use this method with node-webkit the screen flickers between views (it displays whatever programs are running in the background for maybe ~200ms – 300ms). Does anybody know a solution to fix this? I could re-build as a single page app using angularjs – but would prefer if I could keep the structure I have as time is an issue.

    I would really appreciate an input on this.

Leave a Reply

Your email address will not be published. Required fields are marked *