Force npm to install the same dependencies on mutiple machines - node.js

I have a packages.json file and I'm installing the needed node modules with npm install from the same directory where the file is located.
The problem is that I'm doing this on different machines and some of them might already have some dependencies installed globally.
This normally shouldn't represent a problem but in my case it is.
For example I need to install grunt-contrib-uglify and since some machine might already have some dependencies installed they won't try to fetch and get them. This lead to two slightly different versions of the dependencies tree.
Example:
npm list (truncated) produces:
# Machine 1
├─┬ grunt-contrib-uglify#0.2.7
│ ├─┬ grunt-lib-contrib#0.6.1
│ │ └── zlib-browserify#0.0.1
│ └─┬ uglify-js#2.4.21
│ ├── async#0.2.10
│ ├─┬ source-map#0.1.34
│ │ └── amdefine#0.1.0
│ ├── uglify-to-browserify#1.0.2
│ └─┬ yargs#3.5.4
│ ├── camelcase#1.0.2
│ ├── decamelize#1.0.0
│ ├── window-size#0.1.0
│ └── wordwrap#0.0.2
# Machine2
├─┬ grunt-contrib-uglify#0.2.7
│ ├─┬ grunt-lib-contrib#0.6.1
│ │ └── zlib-browserify#0.0.1
│ └─┬ uglify-js#2.4.23
│ ├── async#0.2.10
│ ├─┬ source-map#0.1.34
│ │ └── amdefine#0.1.0
│ ├── uglify-to-browserify#1.0.2
│ └─┬ yargs#3.5.4
│ ├── camelcase#1.1.0
│ ├── decamelize#1.0.0
│ ├── window-size#0.1.0
│ └── wordwrap#0.0.2
In this case camelcase and uglify-js are not exactly the same version.
When I use this in conjunction with grunt to minify the production js files I get minor differences between the compiled files. Of course the two files acts exactly the same but for git they are different (and I would like to avoid this)
Question: how can I tell npm that I want exactly the same modules but also exactly the same dependencies?

There is a file named package-lock.json. It contains the exact dependency tree of all installed packages including the registry where they were downloaded from. Whenever you add a new dependency using npm install <package-name> this file is updated automatically. It should be checked in into your version control.
To make sure that the same package versions listed in the file are installed in your node_modules folder you have to execute the command npm ci (ci = clean install). This is going to delete your node_modules folder and download the exact packages listed int the package-lock.json. This command should be used instead of npm install in any build script.

I've found the solution: npm-shrinkwrap
So, first I should install and test the modules as normally I would with npm install then run npm shrinkwrap to lock down all the installed modules and their deps into a file called npm-shrinkwrap.json. We could use the flag --dev if we want also to save dev deps.
Then we could for example track this file with git and from other machines retrieve the tracked file.
Then normally npm install => If the file npm-shrinkwrap.json is present it will take precedence over packages.json and npm will use it to install exactly all the deps specified in the file.

Related

Determine npm package dependency chain

I run npm install on a project and get a deprecation error for an underlying dependency.
It is not a direct dependency, it's in node_modules. How can I easily figure out which of my dependencies eventually depends on the problematic library?
A first-pass solution is to use grep, but 2 issues:
This will help me locate the package.json containing the problematic dependency, but there could be 2, 3, 4...n packages between that and my own project's package.json
grep is a bit slow
What's wrong with using npm ls? Here's sample output for a module:
➜ node-address-rfc2821 git:(master) npm ls
address-rfc2821#2.0.0 /Users/matt/git/node-address-rfc2821
├─┬ nearley#2.20.1
│ ├── commander#2.20.3
│ ├── moo#0.5.1
│ ├── railroad-diagrams#1.0.0
│ └─┬ randexp#0.4.6
│ ├── discontinuous-range#1.0.0
│ └── ret#0.1.15
└── punycode#2.1.1
The command npm ls has been around since at least 2011

Npm versioning architecture fatally flawed

I am getting this error from npm:
Browserify Failed!: Path must be a string. Received undefined while parsing file:
Because browserify works fine on other dev environments around the office I pretty sure it is a npm version issue. Most likely related to an older babel-core. (ref https://github.com/babel/grunt-babel/issues/56)
The fix is to update babel-core to at least 6.10. Here is the list for babel-core.
├─┬ babelify#7.3.0
│ └─┬ babel-core#6.24.1
│ └─┬ babel-register#6.24.1
│ └── babel-core#6.24.1
├─┬ laravel-elixir#5.0.0
│ ├─┬ babelify#7.2.0
│ │ └── babel-core#6.7.2
│ └─┬ gulp-babel#6.1.2
│ └── babel-core#6.7.2
└─┬ laravel-elixir-vueify#1.0.6
└── babel-core#6.7.6
I need to update the copies of babel-core under laravel-elixir only. So how do I do that?
npm -v = 3.10.10
node -v = v6.10.2

Node.js -- Command not found for installed module

I had node, npm, and http-server installed and running. However, when I tried to start up the http-server, I got the following error:
error: Cannot find module 'child-process-close
I have tried uninstalling and re-installing node. That seemed to work just fine, and it looked like it installed http-server properly when I installed it globally with the following command:
npm install -g http-server
However, when I tried to run the server on a directory (I even installed http-server locally in that directory), I get the following error:
zsh: command not found: http-server
When I run this command:
npm ls -g
I get:
/Users/amckemie1/.node/lib
├─┬ http-server#0.7.4
│ ├── colors#1.0.3
│ ├─┬ ecstatic#0.5.8
│ │ ├── he#0.5.0
│ │ ├── mime#1.2.11
│ │ └── minimist#1.1.0
│ ├── opener#1.4.0
│ ├─┬ optimist#0.6.1
│ │ ├── minimist#0.0.10
│ │ └── wordwrap#0.0.2
│ ├─┬ portfinder#0.2.1
│ │ └── mkdirp#0.0.7
│ └─┬ union#0.4.4
│ └── qs#2.3.3
└─┬ npm#2.3.0
etc...
I can't figure out why it can't find the http-server module. I'm guessing it has something to do with my PATH or where the module was installed, but I don't know enough about these factors yet to be able to do much more. Any ideas?
I found the answer to this question here: Global Node modules not installing correctly. Command not found
Brad Parks answer regarding resetting my node install prefix fixed it!

npm: how are dependencies managed?

I installed express, mongodb, and mongoose.
This is the result of my npm ls:
/home/merc/Bookings
├─┬ connect-mongo#0.1.9
│ └─┬ mongodb#0.9.9-8
│ └── bson#0.0.4
├─┬ express#3.0.0rc2
│ ├── commander#0.6.1
│ ├─┬ connect#2.4.2
│ │ ├── bytes#0.1.0
│ │ ├── formidable#1.0.11
│ │ ├── pause#0.0.1
│ │ └── qs#0.4.2
│ ├── cookie#0.0.4
│ ├── crc#0.2.0
│ ├── debug#0.7.0
│ ├── fresh#0.1.0
│ ├── methods#0.0.1
│ ├── mkdirp#0.3.3
│ ├── range-parser#0.0.4
│ └─┬ send#0.0.3
│ └── mime#1.2.6
├─┬ jade#0.27.2
│ ├── commander#0.6.1
│ └── mkdirp#0.3.0
├─┬ mongodb#1.1.2
│ └── bson#0.1.1
└─┬ mongoose#3.0.0
├── hooks#0.2.1
├─┬ mongodb#1.1.2
│ └── bson#0.1.1
└── ms#0.1.0
You can clearly see that for some reason Jade is on the root directory (I assume this happened when I run "express". But then again, "mongodb" is available in different versions (0.9.9 and 1.1.2) and so is bson (0.1.1 and a worrying 0.0.4).
Hence my questions: how are dependencies managed with npm? Does every package simple install whatever they like, whichever version they pick?
I guess the question is: is this kind of duplication "normal", and "by design" so to speak?
Merc.
The short answer is, yes, this is by design. When you require a module from the node_modules directory, it uses the top-level directory--e.g., whichever one you specify in your package.json.
Other packages have their own package.json files, and are free to use whatever versions they want, and when they require them down in their own code, they will use their own node_modules folder.
Ideally, the modules you use have tests, etc. that ensure that versions (or even specify a range of versions, such as 0.9.x) of dependencies they specify work well, and seeing older versions of sub-dependencies in there doesn't necessarily mean danger, although new versions of these modules could of course potentially fix bugs and so forth. It may be worth finding a module you're concerned about on GitHub, downloading the repository, updating the package.json and dependencies yourself and running the tests to see if a new version works. If so, perhaps the author would be willing to accept a pull request with your update.

Node package ( Grunt ) installed but not available

I'm trying to build a github jquery-ui library using grunt, but after running npm install I still can't run the command according to the readme file. It just gives No command 'grunt' found:
james#ubuntu:~/Documents/projects/ad2/lib/jquery-ui$ grunt build
No command 'grunt' found, did you mean:
Command 'grun' from package 'grun' (universe)
grunt: command not found
james#ubuntu:~/Documents/projects/ad2/lib/jquery-ui$ npm ls
jquery-ui#1.9.0pre /home/james/Documents/projects/ad2/lib/jquery-ui
├─┬ grunt#0.3.9
│ ├── async#0.1.18
│ ├── colors#0.6.0-1
│ ├─┬ connect#1.8.7
│ │ ├── formidable#1.0.9
│ │ ├── mime#1.2.5
│ │ └── qs#0.5.0
│ ├── dateformat#1.0.2-1.2.3
│ ├─┬ glob-whatev#0.1.6
│ │ └─┬ minimatch#0.2.4
│ │ └── lru-cache#1.0.6
│ ├─┬ gzip-js#0.3.1
│ │ ├── crc32#0.2.2
│ │ └── deflate-js#0.2.2
│ ├── hooker#0.2.3
│ ├─┬ jshint#0.5.9
│ │ ├── argsparser#0.0.6
│ │ └─┬ minimatch#0.2.4
│ │ └── lru-cache#1.0.6
│ ├─┬ nodeunit#0.6.4
│ │ ├── tap-assert#0.0.10
│ │ └─┬ tap-producer#0.0.1
│ │ ├── inherits#1.0.0
│ │ ├── tap-results#0.0.2
│ │ └── yamlish#0.0.5
│ ├─┬ nopt#1.0.10
│ │ └── abbrev#1.0.3
│ ├─┬ prompt#0.1.12
│ │ ├── pkginfo#0.2.3
│ │ └─┬ winston#0.5.11
│ │ ├── eyes#0.1.7
│ │ ├─┬ loggly#0.3.11
│ │ │ └── timespan#2.2.0
│ │ └── stack-trace#0.0.6
│ ├── semver#1.0.13
│ ├─┬ temporary#0.0.2
│ │ └── package#1.0.0
│ ├── uglify-js#1.0.7
│ ├── underscore#1.2.4
│ └── underscore.string#2.1.1
├── grunt-compare-size#0.1.4
├─┬ grunt-css#0.2.0
│ ├── csslint#0.9.8
│ └── sqwish#0.2.0
├── grunt-html#0.1.1
├── request#2.9.153
├─┬ rimraf#2.0.1
│ └── graceful-fs#1.1.8
└─┬ testswarm#0.2.2
└── request#2.9.202
I'm confused, what am I missing please?
The command line tools are not included with the latest version of Grunt (0.4 at time of writing) instead you need to install them separately.
This is a good idea because it means you can have different versions of Grunt running on different projects but still use the nice concise grunt command to run them.
So first install the grunt cli tools globally:
npm install -g grunt-cli
(or possibly sudo npm install -g grunt-cli ).
You can establish that's working by typing grunt --version
Now you can install the current version of Grunt local to your project. So from your project's location...
npm install grunt --save-dev
The save-dev switch isn't strictly necessary but is a good idea because it will mark grunt in its package.json devDependencies section as a development only module.
Add /usr/local/share/npm/bin/ to your $PATH
If you did have installed Grunt package by running npm install -g grunt and it still say's No command 'grunt' found or grunt: command not found, a quick and dirty way to get this working is linking node binaries to your $PATH manually.
On MacOSX/Linux you can add this line to your ~/.bash_profile or ~/.bashrc file.
PATH=$PATH:/usr/local/Cellar/node/HEAD/bin # Add NPM binaries
You probably should replace /usr/local/Cellar/node/HEAD/bin by the path where your node binaries could be found.
If this is quick and dirty to me, it's because everything should work without doing this, but for an unknown reason, a link seem broken. As nobody on IRC could tell me why this happened, I found my own way to make it (grunt) work.
PS: This should help you make grunt works, this answer is not jquery-ui related.
Update 02/2013 : You should take a look at #tom-p's answer which explains better what is going on. Tom gives us the real solution instead of hacking your bashrc file : both should work, but you should try installing grunt-cli first.
In my case, i need modify the file /usr/local/bin/grunt in line 1 ( don't make this ):
#!/usr/bin/env node //remove this line
#!/usr/bin/env nodejs // and put this line to run with nodejs
Edited:
To avoid problems, I created a link with the name of "node" because many other programs still use "node" command.
sudo ln -s /usr/bin/nodejs /usr/sbin/node
There is one more way to run grunt on windows, without adding anything globally. This is a case when you don't have to do anything with %PATH%
if you have grunt and grunt-cli installed (without -g switch).
Either by:
npm install grunt-cli
npm install grunt#0.4.5
Or by having that in your packages.json file like:
"devDependencies": {
"grunt-cli": "^1.2.0",
"grunt": "^0.4.5",
You can call grunt from your local installation by:
node node_modules\grunt-cli\bin\grunt --version
This is a solution for those who for some reasons don't want to or can't play with PATH, or have something else messing it all the time, for instance on a build agent.
Edit:
Added versions as the grunt-cli works with grunt > 0.3
On WIN7 I had to manually add the path to the npm folder (which contains the elusive 'grunt' file) to the Windows PATH environmental variable.
In my case that was C:\Users\mhaagsma\AppData\Roaming\npm
Hello I had this problem on mac, and what I did was
installed globally and prefix with global path
sudo npm install grunt -g --prefix=/usr/local
now
$ which grunt
should out put
/usr/local/bin/grunt
Cheers
The right way to install grunt is by running this command:
npm install grunt -g
(Prepend "sudo" to the command above if you get a EACCESS error message)
-g will make npm install the package globally, so you will be able to use it whenever you want in your current machine.
Instala grunt de manera global: sudo npm install -g grunt-cli --unsafe-perm=true --allow-root
Try to run grunt.
If you have this message:
Warning:
You need to have Ruby and Sass installed and in your PATH for this task to work.
More info: https://github.com/gruntjs/grunt-contrib-sass
Used --force, continuing.
3.1. Check that you have ruby installed (mac, you should have it): ruby -v
Sometimes you have to npm install package_name -g for it to work.
Other solution is to remove the ubuntu bundler in my case i used:
sudo apt-get remove ruby-bundler
That worked for me.
On Windows, part of the mystery appears to be where npm installs the Grunt.cmd file. While on my Linux box, I just had to run sudo npm install -g grunt-cli, on my Windows 8 work laptop, Grunt was placed in the '.npm-global' directory: %USER_HOME%\.npm-global and I had to add that to the Path.
So on Windows my steps were:
npm install -g grunt-cli
figure out where the heck grunt.cmd was (I guess for some it is in %USER_HOME%\App_Data\Roaming)
Added the location to my Path environment variable. Opened a new cmd prompt and the grunt command ran fine.
On Windows 10 Add this to your Path:
%APPDATA%\npm
This references the folder ~/AppData/Roaming/npm
[Assumes that you have already run npm install -g grunt-cli]
I installed grunt as a development dependency. For some reason I had the NODE_ENV set to production (eg. export NODE_ENV=production) so when I run npm i what got installed were the production dependencies instead the development dependencies.
To get it fixed all I had to do was to fix the respective environment variable, so by export NODE_ENV=development followed by npm i the development dependencies installed as they should in the first place.
Probably this is a rare case but if nothing else works then it is worth checking these premises too.

Resources