Here's what I would do.
Distribute your program in a traditional archive
- package your program into a distributable archive such as .tar.bz2 (preferred), .tar.gz, or .zip (if it needs to support windows)
- In the archive include node itself, your fully-populated node_modules folder, and all your other javascript modules, files, whatnot
- Because node is platform-dependent, you will thus need a different archive distribution for each target architecture (linux/windows/osx)
- These above are consistent with the 12 Factor App Build/Release/Run principles.
- Include an executable shell script that is your program's entry point that can do something like
Include an executable shell script wrapper
#!/bin/sh
DIR=$(dirname "${0}")
exec "${DIR}/node/bin/node" "${DIR}/main.js" "${@}"
Install via curl command line copy/paste
I noticed in the comments you want a homebrew-style install-via curl command line. In that case, all of the above still applies but your curl command downloads a shell script that does:
- download the distribution archive
- extract it in place (
/usr/local/programname
would be reasonable)
- If necessary, set up symlinks or copy files into a
bin
directory in the user's PATH (/usr/local/bin/programname
would be reasonable)
So your curl command might be curl http://example.com/myprogram/install.sh | sh
Again, this is consistent with the 12 Factor App principles, which are sound. In particular:
- Do not expect the target user to already have node installed
- Do not expect the target user to install node by following your directions
- Do not bother trying to support varying versions of node unless you really have a requirement to do so
- It is OK to bundle node with your app. It makes it easier to install, easier to support, and less prone to errors.
Misc Tips
- Make sure your installer code is idempotent
- You may want to explicitly set the wrapper shell script executable on the target machine with
chmod
in the install.sh
script as zip archives and tar under some circumstances won't preserve that
- Watch out for OS X's crappy old
tar
. Use gnutar
instead.
Reference material
Refer to homebrew's go
ruby program for ideas/inspiration https://raw.github.com/mxcl/homebrew/go
Here are some examples taken from build script in the github repo for my web site
install_node() {
local VERSION=${1-0.10.7}
local PREFIX=${2-node}
local PLATFORM=$(uname | tr A-Z a-z)
case $(uname -p) in
i686)
ARCH=x86
;;
esac
mkdir -p "${PREFIX}"
curl --silent \
"http://nodejs.org/dist/v${VERSION}/node-v${VERSION}-${PLATFORM}-${ARCH}.tar.gz" \
| tar xzf - --strip-components=1 -C "${PREFIX}"
}
task:dist() {
cd "${CODE_PATH}"
local GIT_REF="${1-master}"
local BUILD_DIR="build"
local DIST_DIR="dist"
local PREFIX="${SITE}-${GIT_REF}"
dirs "${BUILD_DIR}" "${DIST_DIR}"
echo doing git archive
git archive --format=tar --prefix="${PREFIX}/" "${GIT_REF}" | \
#extract that archive into a temporary build directory
"${TAR}" --directory "${BUILD_DIR}" --extract
#install node
NODE_VERSION=$(./bin/jsonpath.coffee engines.node)
echo installing node
install_node "${NODE_VERSION}" "${BUILD_DIR}/${PREFIX}/node"
#Note we use npm from the build platform (OS X) here instead of
#the one for the run platform as they are incompatible
echo install npm packages
(cd "${BUILD_DIR}/${PREFIX}" && npm install --silent --production)
echo creating archive
"${TAR}" --directory "${BUILD_DIR}" --create --bzip2 --file "${DIST_DIR}/${PREFIX}.tar.bz2" .
}