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/programnamewould be reasonable)
- If necessary, set up symlinks or copy files into a bindirectory in the user's PATH (/usr/local/bin/programnamewould 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 chmodin theinstall.shscript as zip archives and tar under some circumstances won't preserve that
- Watch out for OS X's crappy old tar. Usegnutarinstead.
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" .
}