简体   繁体   中英

Install NPM into home directory with distribution nodejs package (Ubuntu)

I'd like to use the distribution Node.js packages (or the chris-lea ppa for more recent releases) but install NPM to my home directory.

This may seem picky, but it's a pretty idiomatic way for polyglot/github-using developers to setup language runtime/library environments under Linux: distro packages for the runtime, 3rd-party libraries in per-user environment (see virtualenv, RVM - RVM will also build Ruby for you if you want). If necessary I will build node locally but it's a PITA since Node is becoming an incidental development requirement for lots of projects.

NPM will install local packages into your projects already, but I still like to keep the system away from my operating system's files. Here's how I suggest compartmentalizing Nodejs packages:

Install Nodejs and NPM via the chris-lea PPA. Then I set up a package root in my homedir to hold the Node "global" packages:

 $ NPM_PACKAGES="$HOME/.npm-packages"
 $ mkdir -p "$NPM_PACKAGES"

Set NPM to use this directory for its global package installs:

 $ echo "prefix = $NPM_PACKAGES" >> ~/.npmrc

Configure your PATH and MANPATH to see commands in your $NPM_PACKAGES prefix by adding the following to your.zshrc/.bashrc:

# NPM packages in homedir
NPM_PACKAGES="$HOME/.npm-packages"

# Tell our environment about user-installed node tools
PATH="$NPM_PACKAGES/bin:$PATH"
# Unset manpath so we can inherit from /etc/manpath via the `manpath` command
unset MANPATH  # delete if you already modified MANPATH elsewhere in your configuration
MANPATH="$NPM_PACKAGES/share/man:$(manpath)"

# Tell Node about these packages
NODE_PATH="$NPM_PACKAGES/lib/node_modules:$NODE_PATH"

Now when you do an npm install -g , NPM will install the libraries into ~/.npm-packages/lib/node_modules , and link executable tools into ~/.npm-packages/bin , which is in your PATH .

Just use npm install -g as you would normally:

[justjake@marathon:~] $ npm install -g coffee-script
... (npm downloads stuff) ...
/home/justjake/.npm-packages/bin/coffee -> /home/justjake/.npm-packages/lib/node_modules/coffee-script/bin/coffee
/home/justjake/.npm-packages/bin/cake -> /home/justjake/.npm-packages/lib/node_modules/coffee-script/bin/cake
coffee-script@1.3.3 /home/justjake/.npm-packages/lib/node_modules/coffee-script

[justjake@marathon:~] $ which coffee
/home/justjake/.npm-packages/bin/coffee

Jake's answer was posted in 2012 and while useful it references Chris Lea's Node.js PPAs who are no longer updated since march 2015.

Here's the steps I use to install Node.js and npm in my home directory:

Install Node.js with nvm (no sudo required):

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash
source ~/.bashrc
nvm install 7
npm install -g npm  # update npm

Now you can install -g without sudo and everything goes into ~/.nvm/

Or install Node.js without nvm ( official instructions ):

Install Node.js

  • Node.js v6 (current LTS as of May 2017):

     curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash - sudo apt-get install -y nodejs
  • Node.js v7:

     curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash - sudo apt-get install -y nodejs

Change npm's default directory to a local one:

mkdir ~/.npm-global
npm config set prefix '~/.npm-global'
export PATH="$HOME/.npm-global/bin:$PATH"  # ← put this line in .bashrc
source ~/.bashrc  # if you only updated .bashrc

Alternatively replace .npm-global by the directory of your choice.

Update npm and check it is installed in your $HOME directory:

$ npm install npm -g
/home/<username>/.npm-global/bin/npm -> /home/<username>/.npm-global/lib/node_modules/npm/bin/npm-cli.js
/home/<username>/.npm-global/lib
└─┬ npm@3.10.6 
  ├─┬ glob@7.0.5 
  │ └── minimatch@3.0.2 
  ├── npm-user-validate@0.1.5 
  └── rimraf@2.5.3 

Now you can install -g without sudo and without messing with your system files.

The solution posted by Just Jake is great. However, due to a bug with npm > 1.4.10, it may not work as expected. (See this and this )

While the bug is solved, you can downgrade to npm 1.4.10 by following this steps:

  1. Comment the prefix line in your $HOME/.npmrc
  2. Run sudo npm install -g npm@1.4.10
  3. Ensure that the right version of npm is installed ( npm --version )
  4. Uncomment the prefix line in your $HOME/.npmrc
  5. Proceed to install your global packages in your home folder..

Because python does already a great job virtualenv , I use nodeenv . Compared to nvm , you can create multiple environments for the same node version (eg two environments for node 0.10 but with different sets of packages).

ENVNAME=dev1

#  create an environment
python -m virtualenv ${ENVNAME}

# switch to the newly created env
source ${ENVNAME}/bin/activate

# install nodeenv
pip install nodeenv

# install system's node into virtualenv
nodeenv --node=system --python-virtualenv

The readme is pretty good: https://github.com/ekalinin/nodeenv

I used @just-jake solution for some time and found that nvm is easier to setup. Also it's much powerful solution that allows to install and use different versions of nodejs .

On Ubuntu 14.04 or 16.04:

  1. Install prerequisite packages for building nodejs :

     sudo apt-get update sudo apt-get install build-essential libssl-dev
  2. Install nvm :

     curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.1/install.sh | bash

    In case newer version of nvm will be available you can find actual installation command on nvm site.

  3. nvm installer will add bootstrap script to ~/.bashrc , so you need either to reopen terminal to run it, or to do:

     source ~/.bashrc
  4. Now you can install any nodejs version you like, switch between them etc.

    Use nvm ls-remote to list available nodejs versions.

    To install, for example, nodejs v4.2.4 do:

     # install v4.2.4 nvm install v4.2.4 # use nodejs v4.2.4 in the current terminal session nvm use v4.2.4 # use v4.2.4 by default in new terminal session nvm alias default v4.2.4

As stated already here and here

npm config set prefix ~
echo export PATH=\$PATH:\~/bin >> ~/.bashrc
. ~/.bashrc

Other answers have outdated solutions: 2020's solution is using NPM_CONFIG_PREFIX environment variable. (See details )

For example,

$ NPM_CONFIG_PREFIX="$HOME/.npm-packages" npm install -g ios-sim
/Users/<name>/.npm-packages/bin/ios-sim -> /Users/<name>/.npm-packages/lib/node_modules/ios-sim/bin/ios-sim
+ ios-sim@9.0.0
added 108 packages from 68 contributors in 3.094s

To expand on the answer provided by Just Jake and user1533401: I am unable to downgrade as I use shared hosting and node is installed in a system directory. This is also why I have change the directory where npm installs global scripts if I want it to do that. For those in the same boat, here is a another temporary fix I found works:

npm install -g --prefix=$(npm config get prefix) <package>

The bug is that npm doesn't read your per-user config file, but specifying it every time you install a global script fixes that. Found here .

I have a slightly different solution to a similar problem, which was due to my installing npm globally so I can use it in the Terminal of my macOS system. I simply initialised it locally at the root directory of my repository with the command:

npm init --yes

This did the trick for enabling me to install node packages in the local root directory at /node_modules with the "package.json" and "package-lock.json" files instead of at the user's home directory.

You can use npm-user to automatically set up npm to install packages into your user's directories instead of the system's. No root privileges needed.

Here's a link to the script , instructions on how to use it and information about its options. It works on macOS, Linux, *BSD and Windows.

You can run it like so:

$ curl -s "https://raw.githubusercontent.com/alexdelorenzo/npm-user/main/npm-user.sh" | bash

After you run it, using npm install -g <package> will install packages to your user's directories without needing to use sudo .

Here's the code if you want to copy and paste it into your console:

#!/usr/bin/env bash
# Copyright 2022 Alex DeLorenzo <alexdelorenzo.dev>. Licensed under the GPLv3.
export ROOT="${1:-$HOME}"

export NPM_DIR=".npm-packages"
export NPM_ROOT="$ROOT/$NPM_DIR"
export NPM_BIN="$NPM_ROOT/bin"
export NPM_MAN="$NPM_ROOT/share/man"

export BASH_RC="$HOME/.bashrc"
export ZSH_RC="$HOME/.zshrc"
export DEFAULT_RC="$BASH_RC"

export RC_ERR=1
export INDENT=2

set -e

shopt -s expand_aliases

alias indent="paste /dev/null - | expand -$INDENT"


quiet() {
  "$@" &> /dev/null
}


expand-tilde() {
  local path="$1" 
  echo "${path/#\~/$HOME}"
}


create-paths() {
  local bin="${1:-$NPM_BIN}"
  local man="${2:-$NPM_MAN}"

  mkdir --parents --verbose "$bin" "$man"
}


set-prefix() {
  npm config set prefix "$NPM_ROOT"
}


get-vars() {
  local bin="${1:-$NPM_BIN}"
  local man="${2:-$NPM_MAN}"

  cat <<EOF
export PATH="\$PATH:$bin"
export MANPATH="\${MANPATH:-\$(manpath)}:$man"
export NPM_PACKAGES="$NPM_ROOT"
EOF
}


already-added() {
  local rc="${1:-$DEFAULT_RC}"
  local bin="${2:-$NPM_BIN}"
  local man="${2:-$NPM_MAN}"

  local vars="$(get-vars "$bin" "$man")"
  quiet grep "$vars" "$rc"
}


main() {
  local rc="$(expand-tilde "${1:-$DEFAULT_RC}")"
  local bin="$(expand-tilde "${2:-$NPM_BIN}")"
  local man="$(expand-tilde "${3:-$NPM_MAN}")"

  printf "Creating %s and %s\n" "$bin" "$man"
  create-paths "$bin" "$man" || {
    printf "Couldn't create paths: %s and %s.\n" "$bin" "$man" 
    return $RC_ERR
  }
  
  printf "Setting npm prefix.\n"
  set-prefix || {
    printf "Couldn't set prefix.\n"  
    return $RC_ERR
  }

  if ! already-added "$rc" "$bin" "$man"; then
    printf "Writing to %s.\n" "$rc"
    get-vars "$bin" "$man" >> "$rc"
 
  fi || {
    printf "Unable to write to %s.\n" "$rc"
    printf "Add the following to your shell's configuration file:\n\n"

    get-vars "$bin" "$man" | indent
    return $RC_ERR
  }

  printf "Done.\n\n"
  printf "To load the changes in this shell, run:\n"
  printf "\tsource %s\n" "$rc"
}


main "$2" "$3" "$4"

At least on Ubuntu the default config for system wide npm is that npm install --global tries to install packages to /usr/lib/node_modules . To set different default for your own user account run following once:

mkdir -p ~/.npm/lib/bin
npm config set prefix "~/.npm/lib"

in addition you want following fragment in .profile :

# set PATH so it includes user's private .npm/lib/bin if it exists
if [ -d "$HOME/.npm/lib/bin" ] ; then
    PATH="$HOME/.npm/lib/bin:$PATH"
fi

If you now install something with npm install --global packagename it will end up in correct location and can be found in your PATH (you may need to logout and re-login for .profile changes to take effect).

Of course, you could select some other directory instead. For example ~/.config/npm could make sense for modern systems.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM