Saturday, June 03, 2017

Nw.js vs. Electron

Today, I tried porting an html5 web app of mine into a desktop application. When it comes to running JavaScript programs on the desktop, there are two main choices: node-webkit (nw.js) and Electron. I wasn't sure which one to choose. I didn't think that my web app was very complicated, so I decided to use nw.js. It's simpler, older, has an easier programming model, and I've been happy when I've used apps based on nw.js in the past.

Using nw.js was great. It was so simple and easy to use. I just unzipped nw.js somewhere, dropped my own web pages there, and off it went. It was nothing like the days and days of agony involved in making a Cordova app. The amount of documentation was very manageable, so I was soon diving through it to figure out various polishing issues. And it was all pretty simple. Fixing the taskbar icon was one line. Making it remember the window size from when it was last closed--also one line. Putting in a "save as" dialog was a little more work, but, again, nothing to sweat about.

Then, I decided that I wanted the save dialog to default to saving to Windows' My Documents folder. And that was hours and hours of agony. The nw.js API is pretty small, so I went through all the documentation with a fine-tooth comb, looking for how to do it, and I couldn't find anything. I then thought that maybe that API was in node.js, so I went through all the node.js documentation to find out how to do it--nothing. Then I thought there might be an NPM package to do it. After much searching, I turned up nothing. I think most people use node.js for server stuff, so they never need to store stuff in a user's Documents folder.

After hours of this, I took a peek at Electron, and it was right there. Electron has an extensive platform integration API for not only getting at the documents folder, but also for crazy MacOS dock stuff, etc. Electron is used by bigger companies that ship more complicated applications, so they care deeply about all the subtle platform integration issues needed for a polished app. As a result, Electron has a much deeper and much more extensive platform integration API than nw.js. Of course, the Electron programming model is more complicated than nw.js, so it seems like it will require a lot more code to be written to get things going. And there's a lot more documentation, so I don't think it's possible to read it all, like I could with nw.js. And I'm concerned there might be annoying configuration issues. But it looks like I'll have to move to using Electron.

So if you need extensive platform integration APIs, use Electron, despite the fact that it's more complicated. If you're making something more self-contained, like, say, a game, then nw.js is probably fine though, and you'll save time because it's so easy to set-up.

Update (2017-6-7): Apparently, there's another difference in philosophy between nw.js and Electron too. nw.js tries to create a programming environment that imitates a normal web environment as much as possible. Platform integration is implemented as minor embellishments on existing web APIs with reasonable defaults chosen. With Electron, using normal web APIs will work, but not well. Lots of platform integration features are available, but the programmer has to explicitly write separate Electron code to take advantage of those features, and the API isn't that nice (due to Electron's multi-process architecture and lots and lots of optional parameters). For example, to open a file dialog in nw.js, you can simply reuse the existing html5 file dialog APIs, and the return results are augmented with some extra path information that you can use to open files. To open a file dialog in Electron, you can't reuse your existing html5 file dialog code because Electron's implementation is missing a couple of features, so instead you have to make use of Electron's file dialog APIs. Electron's file dialog APIs are fine, but a little messy to set-up, and by default they aren't modal, so you have to jump through some hoops to get normal file dialog behavior.

Update (2017-8-28): Despite what some people say, the nw.js documentation is much better than the Electron documentation. Electron has a lot of documentation, but it's not well-written. For example, I found the Electron docs would often just list a bunch of method names and method parameter names without really saying what the parameters do (this is similar to the node.js documentation, actually). The documentation that Intel and others have provided for nw.js is very clear and almost a pleasure to read. To show you how good the nw.js documentation is, when I was making a Mac App Store version of an Electron app, I consulted the nw.js documentation on how to do it because the nw.js documentation was just so much more clear and detailed.


  1. What about performance? Any difference?

    1. I didn't do any extensive testing, but for my app, they seemed similar. They both use the same Chromium code underneath, after all. If you end up needing to call a lot of node.js or native APIs, nw.js might theoretically be faster, but my application didn't need to do that, so I don't know.

  2. I need to a cross platform app for super heavy files (3+ tb) between offices. Electron looks better for this, what do you think?

    1. I haven't worked specifically with large files with either Electron or nw.js, but they both use the default Node.js libraries to manipulate files, so I think they would both behave largely the same.

      I found the Node.js "fs" file io library to be underdocumented and a little buggy. I don't know if it even supports 64-bit file pointers. It uses some sort of custom Buffer object to store binary data read from a file. There was supposed to be an arraybuffer underneath the Buffer object, but I found that sometimes that arraybuffer contained garbage data, and so I instead had to access the Buffer object by manually indexing it.

      So basically, I think nw.js and electron will both be equally bad for your use case. You shouldn't use JavaScript for manipulating large amounts of data. Unless your application just works with a small part of large files, then it will likely be too slow. I would suggest starting with nw.js then because it's easier to use, so you'll more quickly discover whether JavaScript will work at all for you. You should first test whether you can even index past the 4GB boundary on large files. There's a chance that you won't be able to. Then I would test to see how long it takes to actually read in and manipulate 1 TB of data in JavaScript. There's a good chance that it will be too slow.