Global Node Modules without sudo
Short post about how to better manage Node Modules Installation for your NodeJS Projects.
It will not only let you install Node Modules without using root privileges but it will also ensure the following benefits of a well managed NodeJS Project:
- Specific Node versions for specific projects
- Specific Node Modules versions for specific projects
- Self-sufficient package.json, no prerequisite needed before
npm install
Background issue
When installing Node Modules globally with npm, you will encounter EACCESS
npm errors:
$ npm install -g whatever
[...]
npm WARN checkPermissions Missing write access to /usr/lib/node_modules/whatever/whatever
[...]
npm ERR! path /usr/lib/node_modules/whatever
npm ERR! code EACCES
npm ERR! errno -13
npm ERR! syscall access
npm ERR! Error: EACCES: permission denied, access '/usr/lib/node_modules/whatever'
npm ERR! { Error: EACCES: permission denied, access '/usr/lib/node_modules/whatever'
npm ERR! stack: 'Error: EACCES: permission denied, access \'/usr/lib/node_modules/whatever\'',
npm ERR! errno: -13,
npm ERR! code: 'EACCES',
npm ERR! syscall: 'access',
npm ERR! path: '/usr/lib/node_modules/@angular/cli/node_modules/whatever' }
npm ERR!
npm ERR! Please try running this command again as root/Administrator.
npm ERR! A complete log of this run can be found in:
npm ERR! /home/user/.npm/_logs/2015-10-21T16_29_42_409Z-debug.log
Below are commonly used solutions to fix this problem.
<spoiler-alert> We use the last one. </spoiler-alert>
Solution 1 :
I, For One, Welcome Our New SuperUser Overlord!
The easiest solution would probably be to surrender and run the install script as root/Administrator, as suggested:
$ sudo npm install -g whatever
This will install your global Node Modules under /usr/lib/node_modules
.
It works... But do you really want to use the root privileges for every global Node Modules you will install?
No, no, no...
Solution 2:
Not So Global Node Modules...
Instead of using root privileges, you may instead move the node_modules
inside your current user home, in a ~/.nvm
directory:
$ mkdir ~/.nvm
$ npm config set prefix '~/.nvm'
Then, at the end of your .profile, make sure you update your PATH:
PATH="$HOME/.nvm/bin:$PATH"
Relaunch your terminal or update your system variables:
$ source ~/.profile
And continue installing global Node Modules under your current user.
Solution 3:
Using Node Version Manager
nvm, Node Version Manager, is a simple bash script to manage multiple active node.js versions.
The beautiful side effect of using nvm
is that the node_modules of each versions will be stored inside the current users's home directory as ~/.nvm/versions/node/vX.Y.Z/lib/node_modules/
. We don't need root privileges to install global Node Modules anymore and we can switch from one Node Version to another, depending on the project.
Installing (or updating) nvm
is as easy as: (check on nvm for the latest nvm version)
wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
Now, after you restart your terminal, install NodeJS (by default, the latest version):
$ nvm install node
Downloading and installing node v9.6.1...
Downloading https://nodejs.org/dist/v9.6.1/node-v9.6.1-linux-x64.tar.xz...
############################################################################################################################################## 100,0%
Computing checksum with sha256sum
Checksums matched!
Now using node v9.6.1 (npm v5.6.0)
Creating default alias: default -> node (-> v9.6.1)
Your global Node Modules will be installed inside ~/.nvm/versions/node/vX.Y.Z/lib/node_modules/
.
You will find more information on how to install specific versions of NodeJS and switching from one to the other here.
Solution 4:
Let the Executor do his job
This is the solution we use!
npx, the Node Package Executor, executes
command
either from a localnode_modules/.bin
, or from a central cache, installing any packages needed in order forcommand
to run.
Yes, it will even install the packages you need to run a command in a central cache if needed!
Example: Using Angular CLI ng
command to create a new Angular Application
You do not need to install Angular CLI globally, you can use npx
to run ng new
before installing the @angular/cli
package:
$ npx -p @angular/cli ng new my-app
create my-app/README.md (1021 bytes)
create my-app/.angular-cli.json (1241 bytes)
[...]
create my-app/src/app/app.component.spec.ts (986 bytes)
create my-app/src/app/app.component.ts (207 bytes)
npm WARN deprecated [email protected]: All versions below 4.0.1 of Nodemailer are deprecated. See https://nodemailer.com/status/
npm WARN deprecated [email protected]: Use uuid module instead
> [email protected] install /home/user/Projects/TEMP/my-app/node_modules/uws
> node-gyp rebuild > build_log.txt 2>&1 || exit 0
> [email protected] install /home/user/Projects/TEMP/my-app/node_modules/node-sass
> node scripts/install.js
Cached binary found at /home/user/.npm/node-sass/4.7.2/linux-x64-59_binding.node
> [email protected] postinstall /home/user/Projects/TEMP/my-app/node_modules/webpack/node_modules/uglifyjs-webpack-plugin
> node lib/post_install.js
> [email protected] postinstall /home/user/Projects/TEMP/my-app/node_modules/node-sass
> node scripts/build.js
Binary found at /home/user/Projects/TEMP/my-app/node_modules/node-sass/vendor/linux-x64-59/binding.node
Testing binary
Binary is fine
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: [email protected] (node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"})
added 1273 packages in 36.111s
That's it! Our Angular application is created and all needed Node Modules have been installed locally. Let's serve our newly created Angular WebApp!
$ ng serve
The program 'ng' is currently not installed. You can install it by typing:
sudo apt install ng-common
Ooooops... But don't run to install ng-common globally yet!!!
You just have to use npx
to run locally installed npm binaries.
$ npx ng serve
Better, you could configure the Shell Auto Fallback inside your .bashrc:
$ npx --shell-auto-fallback bash
command_not_found_handle() {
# Do not run within a pipe
if test ! -t 1; then
>&2 echo "command not found: $1"
return 127
fi
if which npx > /dev/null; then
echo "$1 not found. Trying with npx..." >&2
else
return 127
fi
if ! [[ $1 =~ @ ]]; then
npx --no-install "$@"
else
npx "$@"
fi
return $?
}
$ npx --shell-auto-fallback bash >> ~/.bashrc
$ source ~/.bashrc
Now, if the command is not found, it will try to find it within the installed npm binaries.
$ ng serve
ng not found. Trying with npx...
not found: ng
$ cd my-app
$ ng serve
ng not found. Trying with npx...
** NG Live Development Server is listening on localhost:4200, open your browser on http://localhost:4200/ **
Date: 2018-03-01T08:48:23.771Z
Hash: ac1c4647111e56cc4df3
Time: 7485ms
chunk {inline} inline.bundle.js (inline) 3.85 kB [entry] [rendered]
chunk {main} main.bundle.js (main) 20.8 kB [initial] [rendered]
chunk {polyfills} polyfills.bundle.js (polyfills) 549 kB [initial] [rendered]
chunk {styles} styles.bundle.js (styles) 42.2 kB [initial] [rendered]
chunk {vendor} vendor.bundle.js (vendor) 8.45 MB [initial] [rendered]
webpack: Compiled successfully.
Your Angular WebApp is now running on http://localhost:4200
The npx
Fallback can also work with Node Modules that have not been installed, if you specify the version:
$ cowsay "Steemit is bad"
cowsay not found. Trying with npx...
not found: cowsay
$ cowsay@latest "Steemit is cool"
cowsay@latest not found. Trying with npx...
npx: installed 9 in 1.23s
_________________
< Steemit is cool >
-----------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
And, if you check inside your current global node_modules
, it only contains npm
:
$ ls /home/user/.nvm/versions/node/v9.6.1/lib/node_modules/
npm
Advantages of using nvm and npx
Here are the main advantages of using nvm
(Node Version Manager) and npx
(Node Package Executor):
- Specific Node versions for specific projects
- Specific Node Modules versions for specific projects
- Self-sufficient package.json, no prerequisite needed before
npm install
References
- nvm - the Node Version Manager
- npx - the Node Package Executor
- Angular CLI - Angular Command Line Interface
Congratulations @thierrydd! You have completed some achievement on Steemit and have been rewarded with new badge(s) :
You published your First Post
You made your First Comment
You got a First Vote
Click on any badge to view your own Board of Honor on SteemitBoard.
For more information about SteemitBoard, click here
If you no longer want to receive notifications, reply to this comment with the word
STOP
Thank you Thierrydd for sharing your knowledge on this.
Thank you!!!