Global Node Modules without sudo

in #node7 years ago (edited)

Short post about how to better manage Node Modules Installation for your NodeJS Projects.

<p dir="auto">It will not only let you install Node Modules <strong>without using root privileges but it will also ensure the following benefits of a well managed NodeJS Project: <ul> <li>Specific Node versions for specific projects <li>Specific Node Modules versions for specific projects <li>Self-sufficient package.json, no prerequisite needed before <code>npm install <h1>Background issue <p dir="auto"><br /> <p dir="auto">When installing Node Modules globally with npm, you will encounter <code>EACCESS npm errors: <pre><code>$ 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 <p dir="auto"><br /> <p dir="auto">Below are commonly used solutions to fix this problem. <p dir="auto"><em><strong><spoiler-alert> We use the last one. <strong></spoiler-alert> <h1>Solution 1 : <br />I, For One, Welcome Our New SuperUser Overlord! <p dir="auto"><br /> <p dir="auto">The easiest solution would probably be to surrender and run the install script as root/Administrator, as suggested: <pre><code>$ sudo npm install -g whatever <p dir="auto"><br /> <p dir="auto">This will install your global Node Modules under <code>/usr/lib/node_modules. <p dir="auto">It works... But do you really want to use the root privileges for every global Node Modules you will install? <p dir="auto">No, no, no... <p dir="auto"><img src="https://images.hive.blog/768x0/https://steemitimages.com/DQmPPKmwuQ8UbFgtuQJB8Nxmg8oJSUPbAr89HHLZBGjR62P/image.png" srcset="https://images.hive.blog/768x0/https://steemitimages.com/DQmPPKmwuQ8UbFgtuQJB8Nxmg8oJSUPbAr89HHLZBGjR62P/image.png 1x, https://images.hive.blog/1536x0/https://steemitimages.com/DQmPPKmwuQ8UbFgtuQJB8Nxmg8oJSUPbAr89HHLZBGjR62P/image.png 2x" /> <h1>Solution 2:<br />Not So Global Node Modules... <p dir="auto"><br /> <p dir="auto">Instead of using root privileges, you may instead move the <code>node_modules inside your current user home, in a <code>~/.nvm directory: <pre><code>$ mkdir ~/.nvm $ npm config set prefix '~/.nvm' <p dir="auto"><br /> <p dir="auto">Then, at the end of your .profile, make sure you update your PATH: <pre><code>PATH="$HOME/.nvm/bin:$PATH" <p dir="auto"><br /> <p dir="auto">Relaunch your terminal or update your system variables: <pre><code>$ source ~/.profile <p dir="auto"><br /> <p dir="auto">And continue installing global Node Modules under your current user. <h1>Solution 3:<br />Using Node Version Manager <p dir="auto"><br /> <p dir="auto"><a href="https://github.com/creationix/nvm" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">nvm, Node Version Manager, is a simple bash script to manage multiple active node.js versions. <p dir="auto">The beautiful side effect of using <code>nvm is that the node_modules of each versions will be stored inside the current users's home directory as <code>~/.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. <p dir="auto">Installing (or updating) <code>nvm is as easy as: (check on <a href="https://github.com/creationix/nvm" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">nvm for the latest nvm version) <pre><code>wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash <p dir="auto"><br /> <p dir="auto">Now, after you restart your terminal, install NodeJS (by default, the latest version): <pre><code>$ 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) <p dir="auto"><br /> <p dir="auto">Your global Node Modules will be installed inside <code>~/.nvm/versions/node/vX.Y.Z/lib/node_modules/. <p dir="auto">You will find more information on how to install specific versions of NodeJS and switching from one to the other <a href="https://github.com/creationix/nvm" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">here. <h1>Solution 4:<br /> Let the Executor do his job <p dir="auto"><br /> <p dir="auto"><strong>This is the solution we use! <blockquote> <p dir="auto"><a href="https://www.npmjs.com/package/npx" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">npx, the Node Package Executor, executes <code>command either from a local <code>node_modules/.bin, or from a central cache, installing any packages needed in order for <code>command to run. <p dir="auto">Yes, it will even install the packages you need to run a command in a central cache if needed! <p dir="auto"><strong>Example: Using <a href="https://cli.angular.io" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Angular CLI <code>ng command to create a new Angular Application <p dir="auto">You do not need to install Angular CLI globally, you can use <code>npx to run <code>ng new before installing the <code>@angular/cli package: <pre><code>$ 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 nodemailer@2.7.2: All versions below 4.0.1 of Nodemailer are deprecated. See https://nodemailer.com/status/ npm WARN deprecated node-uuid@1.4.8: Use uuid module instead > uws@9.14.0 install /home/user/Projects/TEMP/my-app/node_modules/uws > node-gyp rebuild > build_log.txt 2>&1 || exit 0 > node-sass@4.7.2 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 > uglifyjs-webpack-plugin@0.4.6 postinstall /home/user/Projects/TEMP/my-app/node_modules/webpack/node_modules/uglifyjs-webpack-plugin > node lib/post_install.js > node-sass@4.7.2 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: fsevents@1.1.3 (node_modules/fsevents): npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.1.3: wanted {"os":"darwin","arch":"any"} (current: {"os":"linux","arch":"x64"}) added 1273 packages in 36.111s <p dir="auto"><br /> <p dir="auto">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! <pre><code>$ ng serve The program 'ng' is currently not installed. You can install it by typing: sudo apt install ng-common <p dir="auto"><br /> <p dir="auto">Ooooops... But don't run to install ng-common globally yet!!! <p dir="auto">You just have to use <code>npx to run locally installed npm binaries. <pre><code>$ npx ng serve <p dir="auto"><br /> <p dir="auto">Better, you could configure the Shell Auto Fallback inside your .bashrc: <pre><code>$ 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 <p dir="auto"><br /> <p dir="auto">Now, if the command is not found, it will try to find it within the installed npm binaries. <pre><code>$ 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. <p dir="auto"><br /> <p dir="auto">Your Angular WebApp is now running on <a href="http://localhost:4200" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">http://localhost:4200 <p dir="auto">The <code>npx Fallback can also work with Node Modules that have not been installed, if you specify the version: <pre><code>$ 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 | || || <p dir="auto"><br /> <p dir="auto">And, if you check inside your current global <code>node_modules, it only contains <code>npm: <pre><code>$ ls /home/user/.nvm/versions/node/v9.6.1/lib/node_modules/ npm <p dir="auto"><br /> <h1>Advantages of using nvm and npx <p dir="auto">Here are the main advantages of using <code>nvm (Node Version Manager) and <code>npx (Node Package Executor): <ul> <li>Specific Node versions for specific projects <li>Specific Node Modules versions for specific projects <li>Self-sufficient package.json, no prerequisite needed before <code>npm install <h1>References <ul> <li><a href="https://github.com/creationix/nvm" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">nvm - the Node Version Manager <li><a href="https://www.npmjs.com/package/npx" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">npx - the Node Package Executor <li><a href="https://cli.angular.io" target="_blank" rel="nofollow noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">Angular CLI - Angular Command Line Interface
Sort:  

Congratulations @thierrydd! You have completed some achievement on Steemit and have been rewarded with new badge(s) :

<p dir="auto"><a href="http://steemitboard.com/@thierrydd" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link"><img src="https://images.hive.blog/768x0/https://steemitimages.com/70x80/http://steemitboard.com/notifications/firstpost.png" srcset="https://images.hive.blog/768x0/https://steemitimages.com/70x80/http://steemitboard.com/notifications/firstpost.png 1x, https://images.hive.blog/1536x0/https://steemitimages.com/70x80/http://steemitboard.com/notifications/firstpost.png 2x" /> You published your First Post<br /> <a href="http://steemitboard.com/@thierrydd" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link"><img src="https://images.hive.blog/768x0/https://steemitimages.com/70x80/http://steemitboard.com/notifications/firstcomment.png" srcset="https://images.hive.blog/768x0/https://steemitimages.com/70x80/http://steemitboard.com/notifications/firstcomment.png 1x, https://images.hive.blog/1536x0/https://steemitimages.com/70x80/http://steemitboard.com/notifications/firstcomment.png 2x" /> You made your First Comment<br /> <a href="http://steemitboard.com/@thierrydd" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link"><img src="https://images.hive.blog/768x0/https://steemitimages.com/70x80/http://steemitboard.com/notifications/firstvoted.png" srcset="https://images.hive.blog/768x0/https://steemitimages.com/70x80/http://steemitboard.com/notifications/firstvoted.png 1x, https://images.hive.blog/1536x0/https://steemitimages.com/70x80/http://steemitboard.com/notifications/firstvoted.png 2x" /> You got a First Vote <p dir="auto">Click on any badge to view your own Board of Honor on SteemitBoard.<br /> For more information about SteemitBoard, click <a href="https://steemit.com/@steemitboard" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">here <p dir="auto">If you no longer want to receive notifications, reply to this comment with the word <code>STOP <blockquote> <p dir="auto">Upvote this notification to help all Steemit users. Learn why <a href="https://steemit.com/steemitboard/@steemitboard/http-i-cubeupload-com-7ciqeo-png" target="_blank" rel="noreferrer noopener" title="This link will take you away from hive.blog" class="external_link">here!

Thank you Thierrydd for sharing your knowledge on this.

Thank you!!!