[Home] [Blog] [Contact] - [Talks] [Workshop] [Bio] [Customers]
twitter linkedin youtube github rss

Patrick Debois

Compiling a nodejs projects as a single binary

Let’s face it, if you write software it’s often hard to distribute it: you have the runtime , the modules you depend on and your software itself. Sure you can package that all but packages ofter require you to have root-privileges to install.

Therefore at times it’s convenient to have a single file/binary distribution. Download the executable and run it. For ruby project you can convert things into a single jar using Jruby. A good example is the logstash project: download 1 file , run it and you’re in business. But you’d still require the java runtime to be installed. (thanks Apple, NOT).

This is a extra of the GO language but I was looking for a similar thing for nodejs. And the following documentation is the closest I could it get: (it works!)

Compiling plain javascript (no external modules)

Enter nexe a tool to compile nodejs projects to an executable binary.

The way it works is:

  • it downloads the nodejs source of your choice
  • it creates a single file nodejs source (using sardines )
  • it monkey patches the nodejs code to include this single file in the binary (adding it to the lib/nexe.js directory)

Creating a binary is as simple as:

$ nexe -i myproject.js -o myproject.bin -r 0.10.3

Caveats:

  • I had an issue with unicode chars that got converted: it uses uglify.js and this needs to be configured to leave them alone Sardines Patch Unichode . This was necessary to get terminal.js to compile
  • Next issue was to get socket.io-client to compile: the swfobject has document and navigator objects, so this had to be fixed as well - Sardines Patch Document & Navigator
  • For now, you’ll need to execute nexe inside the nxe directory and not in the project directory - I think it’s because sardines looks at the package.json file for names

Alternatives:

Embedding a native module (in the nodejs binary)

Many of these single packaging tools, suffer from the problem of handline native modules.

nexe doesn’t handle native modules (yet).

But with a little persistance and creativity, this is what I did to add the pty.js native module directly to the nodejs binary

$ tar -xzvf node-v0.8.21.tar.gz
$ cd node-v0.8.21

# Copy the native code in the src directory
# If there is a header file copy/adapt it too
$ cp ~/dev/terminal.js/node_modules/pty.js/src/unix/pty.cc src/node_pty.cc

# Correct the export name of the module
# Add the node_ prefix to the node_module name
# Last line should read - NODE_MODULE(node_pty, init)

# add node_pty to src/node_extensions.h (f.e. right after node_zlib)
# NODE_EXT_LIST_ITEM(node_pty)

# Copy the pty.js file
$ cp ~/dev/pty.js/lib/pty.js lib/pty.js

# Add the pty.js to the node.gyp
# Somewhere in the library list add pty.js
# Somewhere in the source list add node_pty.cc

# Adapt the namings/bindings in lib/pty.js
# 1) replace: var pty = require('../build/Release/pty.node');
#    with: var binding = process.binding('pty');
# 2) replace all references to pty. to binding.

$ make clean
$ ./configure
$ make

Now you have a custom build node in out/Release/node The filesize was about 10034856 , you can further strip it and 6971192 (6.6M)

Now you need to remove the native dependency from your package.json before you nexe build it

Packaging the file

A single binary now makes it easy to to make a curl installer from it as it only requires you to download file. Remember the caveat of this.

And you can still package it up:

Extras

Rant about why it’s a good or bad Idea - Secure Nodejs distribution

More info on the process.binding:

Convert nodejs projects to single file/beautifier:

Cross compiling: