How to run npm without sudo

By: Ryan Wong at

I found this script which will allow you run npm without being sudo.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/bin/sh

usage()
{
cat << EOF
usage: $0 [-d] [-v]

This script is intended to fix the common problem where npm users
are required to use sudo to install global packages.

It will backup a list of your installed packages remove all but npm,
then create a local directory, configure node to use this for global installs
whilst also fixing permissions on the .npm dir before, reinstalling the old packages.

OPTIONS:
-h Show this message
-d debug
-v Verbose
EOF
}


DEBUG=0
VERBOSE=0
while getopts "dv" OPTION
do
case $OPTION in
d)
DEBUG=1
;;
v)
VERBOSE=1
;;
?)
usage
exit
;;
esac
done

to_reinstall='/tmp/npm-reinstall.txt'

if [ 1 = ${VERBOSE} ]; then
printf "\nSaving list of existing global npm packages\n"
fi

#Get a list of global packages (not deps)
#except for the npm package
#save in a temporary file.
npm -g list --depth=0 --parseable --long | cut -d: -f2 | grep -v '^npm@\|^$' >$to_reinstall

if [ 1 = ${VERBOSE} ]; then
printf "\nRemoving existing packages temporarily - you might need your sudo password\n\n"
fi
#List the file
#replace the version numbers
#remove the newlines
#and pass to npm uninstall

uninstall='sudo npm -g uninstall'
if [ 1 = ${DEBUG} ]; then
printf "Won't uninstall\n\n"
uninstall='echo'
fi
if [ -s $to_reinstall ]; then
cat $to_reinstall | sed -e 's/@.*//' | xargs $uninstall
fi

defaultnpmdir="${HOME}/.npm-packages"
npmdir=''

read -p "Choose your install directory. Default (${defaultnpmdir}) : " npmdir

if [ -z ${npmdir} ]; then
npmdir=${defaultnpmdir}
else
if [ ! -d ${npmdir} ]; then
echo "${npmdir} is not a directory."
exit
fi
npmdir="${npmdir}/.npm-packages"
fi

if [ 1 = ${VERBOSE} ]; then
printf "\nMake a new directory ${npmdir} for our "-g" packages\n"
fi

if [ 0 = ${DEBUG} ]; then
mkdir -p ${npmdir}
npm config set prefix $npmdir
fi

if [ 1 = ${VERBOSE} ]; then
printf "\nFix permissions on the .npm directories\n"
fi

me=`whoami`
sudo chown -R $me ~/.npm

if [ 1 = ${VERBOSE} ]; then
printf "\nReinstall packages\n\n"
fi

#list the packages to install
#and pass to npm
install='npm -g install'
if [ 1 = ${DEBUG} ]; then
install='echo'
fi
if [ -s $to_reinstall ]; then
cat $to_reinstall | xargs $install
fi

envfix='
NPM_PACKAGES="%s"
NODE_PATH="$NPM_PACKAGES/lib/node_modules:$NODE_PATH"
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 config
MANPATH="$NPM_PACKAGES/share/man:$(manpath)"
'


fix_env() {
if [ -f "${HOME}/.bashrc" ]; then
printf "${envfix}" ${npmdir} >> ~/.bashrc
printf "\nDon't forget to run 'source ~/.bashrc'\n"
fi
if [ -f "${HOME}/.zshrc" ]; then
printf "${envfix}" ${npmdir} >> ~/.zshrc
printf "\nDon't forget to run 'source ~/.zshrc'\n"
fi

}

echo_env() {
printf "\nYou may need to add the following to your ~/.bashrc / .zshrc file(s)\n\n"
printf "${envfix}\n\n" ${npmdir}
}

printf "\n\n"
read -p "Do you wish to update your .bashrc/.zshrc file(s) with the paths and manpaths? [yn] " yn
case $yn in
[Yy]* ) fix_env;;
[Nn]* ) echo_env;;
* ) echo "Please answer 'y' or 'n'.";;
esac

rm $to_reinstall

printf "\nDone - current package list:\n\n"
npm -g list -depth=0