| Date: | 2011-03-31 |
|---|---|
| category: | Programming |
| tags: | Ubuntu, Debian, Node.js |
Note
The bundle-command, on which this guide relies heavily has been removed
in the 1.0 version of NPM. It seems to have been superseded by npm
install, as it does now install packages in node_modules - but I
haven't gotten around to test it thoroughly.
Getting Node.js and NPM up and running on Ubuntu isn't hard. Writing working code is a bit harder (I'm a Python convertee), but not that hard.
But persuading the system administrators to actually run your software is something entirely different:
- Me:
- I have written the best software in the world! And I hereby grant you the honor of running it on your servers. Oh, by the way: it's in JavaScript.
- Sysadmin:
- JavaScript... Server... WTF!?
- Me:
- Explains why Node.js is great
- Sysadmin:
- If you say so. Gimme' a Debian package then, and you're good to go.
- Me:
- Ehhh. Can I get back to you?
While Debian has packaging policies for Java, Perl and Python, there is no
such thing for Node.js. (As to Node.js itself, there's Bug 611698, which basically
states that the binary name node has already been used by a different
program, why they package Node.js' binary as nodejs. We have a plan to get
around that; I'll post on that once we get there.)
So. I needed to come up with some way to package Node.js programs in Debian. But how?
Well. I had time, but I didn't really fancy packaging every single Node.js module as individual Debian packages. They're very different beasts, each having their own quirks. The sheer number of dependencies isn't appealing either. And not least, there is a lot of them (1514 at time of writing).
NPM and Node.js to the rescue!
Update 1/4 2011: This is explained way better in Global vs Local installation on the Node.js blog. Read that and skip the next three paragraphs...
It turns out that Node.js version 0.4 and later, gives special treatment to
folders called node_modules. Namely it looks in such folders, when you're
importing modules in your code, thus making local versions of packages, among
other things, a breeze. The documentation explains this nicely.
NPM uses this feature to power it's bundle-command. If you install your
program by issuing npm bundle install (instead of the regular npm
install), it'll put your program's dependencies in ./node_modules,
instead of wherever it usually puts them. This gives you a nicely
compartmentalized environment that works fairly transparently from within
node. (The placement of bundled binaries is a bit odd, but that's a minor
detail).
In all, npm bundle fetches all the program's dependencies to a known,
self-contained and location. We can then trow all of that into a single
deployable package, that will contain everything needed, except the Node.js
binary itself.
First, you should have a package.json file describing your program. NPM
uses this to keep track of dependencies and all the other housekeeping stuff:
{
"name": "foo",
"description": "some text",
"dependencies": {
"underscore": "*",
"vows": "*"
}
}
If you haven't got such a file, use npm init to get started.
Then we need to set up the basic Debian setup going. You can use the program dh-make to get a basic "debianized package" in no time:
dh_make -e YOUR@EMAIL.TLD -s -n -p YOUR-PACKAGE-NAME_0.0.1
Last thing needed is to create/edit a Makefile, which install target
does some Debian-related magic. (The package-building scripts expect make
install DESTDIR=some/temp/dir to do something sensible):
install:
# Create parent directories
install -d $(DESTDIR)/usr/share/YOUR-PACKAGE-NAME/
# Create and copy over node_modules, so node will find it later.
@npm bundle install
cp -r node_modules $(DESTDIR)/usr/share/YOUR-PACKAGE-NAME/
# Copy your own program...
cp -r lib $(DESTDIR)/usr/share/YOUR-PACKAGE-NAME/
install some_binary.js $(DESTDIR)/usr/share/YOUR-PACKAGE-NAME/
If you want to customize how things happen, debian/rules is the place to
hack.
Then you can use dpkg-buildpackage to build your package. The -uc and
-us parameters indicates that you're not signing the resulting souce and
binary packages:
dpkg-buildpackage -uc -us
After tonnes of output, there should be a fresh .deb-file in the parent
directory, which you can try to install it:
``dpkg -i ../YOUR-PROJECT-NAME_0.0.1_i386.deb``.
For further tinkering with the debian/*-files, the Debian New Maintainers'
Guide is the place to look. In
particular, debian/control and debian/changelog is where the fun
stuff happens.
I am neither a Debian nor Node.js, nor NPM guru at any level, so your milage may vary. I'm also quite sure I have missed several corner-cases (it just can't be this simple!).
If you have any suggestions or improvements - or make up something better altogether, please drop me a note, and I'll incorporate it here, post a link or whatever.
Hello,
Interesting thoughts, anyway that the way I use to make my Node.js debian package for ARM processors : https://github.com/itwars/nodejs-ARM and I use an awesome ruby tool call fpm to make it (see my vagrant script https://github.com/itwars/Nodejs-ARM-builder). fpm is also made to make npm -> deb packages !
As I mention on my Node.js site there's another tool call npm2debian : http://www.nodejs-news.com/nodejs-tech/nodejs-debian/
I hope this could help you.
Bests,