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!)
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
- 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
- Node-webkit to package nodejs apps that require UI interaction
- http://tidesdk.multipart.net/docs/user-dev/generated/ - seems similar but could not really grasp it
- NPKG - https://github.com/wearefractal/npkg - old but interesting code
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:
- create a rpm, deb, etc.. package from it using fpm
- or create a native MacOSX .app file from it as Matthias Bynens suggest in http://mathiasbynens.be/notes/shell-script-mac-apps
- build a DMG - http://www.recital.com/index.php?option=com_content&view=article&id=108%3Ahowto-build-a-dmg-file-from-the-command-line-on-mac-os-x&Itemid=59
More info on the process.binding:
Convert nodejs projects to single file/beautifier:
- Npk - https://github.com/cfsghost/npk
- UglifyJS - https://github.com/mishoo/UglifyJS/
- RequireJS - http://requirejs.org/
- Browserify - http://browserify.org/
- OneJS - https://github.com/azer/onejs