First encounter

Update: Atom-shell is now knwon as Electron, and has a brand new website: electron.atom.io.

Atom-shell vs other node/chromium runtime technologies

Atom-shell is a framework based on node.js that include Chromium for rendering web page as well as for desktop integration. We can roughly state that it combines both the server-side and the client-side to build great multi-purpose desktop application.

From Atom-shell creators:

You could also see it as a minimal Chromium browser, controlled by JavaScript.

It is backed by Github, and looks promising. It all begins as a specific framework for the Atom IDE, but it has quickly proven that its goal was to provide a great framework for a large variety of desktop application.

It is one of the three frameworks doing that, namely nw.js, formerly known as node-webkit, and brackets-shell by Adobe.

I have discarded brackets-shell early in the process, because Adobe seems to develop it only for the brackets IDE purpose. There was no guarantee that it will be improved in the long run, neither that it will be developed as a multi-purpose framework in mind. Also in the past, I have been highly frustrated with the Adobe's way of documenting things... I remember Adobe AIR, and frankly: I don't want to experience such a pain again...

Also from their own overview:

Note: The brackets-shell is only maintained for use by the Brackets project. Although some people have definitely had success using it as an app shell for other projects, we don't provide any official support for that and we haven't done a ton of work to make the app shell easily reusable. Many people will likely find it easier to use a project like node-webkit, which is more generic by design.

This notice alone convinced me to stay away from that, forever.

But here is the serious challenger: node-webkit a.k.a. nw.js.

This framework already have a dozen of real life application, and there is even a game in the Steam store.

Node-webkit was built on top of node.js and webkit, hence the name. However it doesn't use any of them anymore: now it's based on io.js, the node.js' fork featuring Harmony (ECMA-Script 6), and Chromium. So they decided to rename it nw.js to avoid confusion.

The governance of nw.js looks more open than it used to be, which is a very good news. On the other hand Github is THE reference of open source collaboration: so we can expect a lot from the atom-shell's community in the future.

Technically, both projects are awesome.

It is not clear which one is better.

But I tend to prefer Atom-shell because its paradigm is more natural to me, particularly those points:

  • The entry point of the application is a Javascript file, not an HTML file: in my opinion this is cleaner

  • We can roughly state that it is the back-end that controle the entire application and I like that (I can be biased here, since I'm a back-end developer)

  • Consequently the back-end can create as many windows as it is needed... If I'm not wrong, nw.js has a main window that cannot be closed without closing the whole application, and new windows should be created by this main window. I found that a bit hacky...

  • The way node.js and Chromium are integrated together is easier and the KISS principle is something I care a lot in computer science... See the details of the integration here.

  • Multi-context, see the Atom-shell documentation:

    If you are an experienced Node-Webkit user, you should be familiar with the concept of Node context and web context, these concepts were invented because of how the Node-Webkit was implemented.

    By using the multi-context feature of Node, atom-shell doesn't introduce a new JavaScript context in web pages.

  • I found the API more cleaner and straightforward, typically the back-end side (named browser-side in the doc) controle a browser, can create windows, close them, define how they look, it can make it interact with the user's desktop... Everything look less hacky and natural. With nw.js it's like a webpage having eventually access to node.js' stuff, with Atom-shell we code like we will do in any other technologies (like for example the C++/GTK combo): it's more like coding a node.js application that can create windows with webpage. I prefer that coding paradigm, the other way is like looking upside-down.

For all those reasons, despite the popularity of nw.js, I decided to go with Atom-shell, after experimenting both of them few hours. There is no large application using Atom-shell at the moment, except Atom itself, but I bet on it...

Letter

Atom-shell: the browser-side and the renderer-side concept

The key to understand Atom-shell is the concept of browser-side (our good ol' back-end/server side) and renderer-side (also called web page, our good ol' front-end/client side).

The first deals with the system and controle the application globally, the second renders a web application in the window created by the first.

Both of them have access to node.js nonetheless, however it is possible to forbid that for a web page, for security reason, if our application is designed to browse some arbitrary website on the internet, rather than run local web content.

For browser to client interaction, we have to use either the IPC module (Inter-Process Communication) which is asynchronous, or the remote module for synchronous RPC (Remote Procedure Call).

The IPC module is familiar to any web developer: it's more or less the same paradigm as the client/server one. Asynchronous content is sent back and forth.

The remote module is easier, we can typically call any method of the browser-side from the renderer-side, just like if both side was the same entity... but be careful: there are some drawbacks!

Let's get our hands dirty!!!

After a week with Atom-shell, playing and coding seriously, there are few things worth mentioning here.

The remote module is really handy, however the only way to gain access to an object of the browser-side is to use remote.getGlobal(name) which bind a global browser-side variable to its renderer-side counterpart. I don't like to pollute the global scope just to provide some objects to the renderer's remote module...

I would prefer passing those objects at the BrowserWindow's instanciation, or as an extra parameter of .loadUrl().

I have created an issue for that, if you like the idea, please contribute to the discussion.

Also there is the problem of callbacks passed to the browser, see here for details.

While I understand what happen and how to avoid it, this forbid the usage of my lovely node.js' EventEmitter. I came up with this kind of design, before reading why it should be avoided:

// Renderer-side code:
var bridge = remote.getGlobal( 'bridge' ) ;
bridge.on( 'update' , function() {
    // do something
} ) ;

That kind of design is really neat, but forbidden... I wonder if it's worth trying to fix the potential exceptions issues with some boilerplated try-catch block, or if it's a definitive no-go...

Trouble with jQuery and workaround

In Atom-shell, we cannot include jQuery like we do usually, i.e. putting <script src="/js/jquery.js"></script> into the main .html file of the renderer-side.

At first glance, it was a bit frustrating, since the renderer/web page side claims to behave like any normal browser. However, it is not an Atom-shell issue. Actually jQuery detect a module and a module.exports global, and therefore expect a CommonJS context, thus decide to not install itself into window.$ as usual.

After a bit of googling, the workaround is easy, we have to require jQuery in the main .js file of the web page, this way:
window.$ = require( '/js/jquery.js' ) ;

For the record, here is the related issue on Github, giving all the details.

Conclusions?

I cannot say I'm an experienced Atom-shell developer at the moment. There are many things to explore, and a great app to build.

But I can say I enjoy it: it just does the job, and that's what we like. There is no fuss, I didn't find anything opinionated, or anything.

Just node.js and Chromium, together.

... to be continued...

Do not miss the other post on Atom-Shell / Electron: