Reputation: 2232
my setup is the following:
bower
installation{
"name": "gadada",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "me",
"dependencies": {
"bower": "latest",
},
"devDependencies": {
}
}
Since I can not properly install those modules in the web directory, because there is a known issue with the synched folders and npm, I want to install them globally. No harm done, because it is a dedicated virtual machine for one and only one web app.
So I do:
sudo npm install -g
Afterwards I try to use bower
, which isn't working, because it did not get linked during npm install.
It works fine when I do
sudo npm install -g bower@latest
What am I doing wrong?
Upvotes: 1
Views: 1277
Reputation: 2232
Okay, I found out, that npm does not work that way. You can not install dependency command line tools globally from a package.json. Thank you for pointing that out, @Matthew Bakaitis
I dug through the npm code yesterday and found a piece of code that explains this behavior:
var linkStuff = build.linkStuff = function (pkg, folder, global, didRB, cb) {
// allow to opt out of linking binaries.
if (npm.config.get('bin-links') === false) return cb()
// if it's global, and folder is in {prefix}/node_modules,
// then bins are in {prefix}/bin
// otherwise, then bins are in folder/../.bin
var parent = pkg.name && pkg.name[0] === '@' ? path.dirname(path.dirname(folder)) : path.dirname(folder)
var gnm = global && npm.globalDir
var gtop = parent === gnm
log.info('linkStuff', packageId(pkg))
log.silly('linkStuff', packageId(pkg), 'has', parent, 'as its parent node_modules')
if (global) log.silly('linkStuff', packageId(pkg), 'is part of a global install')
if (gnm) log.silly('linkStuff', packageId(pkg), 'is installed into a global node_modules')
if (gtop) log.silly('linkStuff', packageId(pkg), 'is installed into the top-level global node_modules')
shouldWarn(pkg, folder, global, function () {
asyncMap(
[linkBins, linkMans, !didRB && rebuildBundles],
function (fn, cb) {
if (!fn) return cb()
log.verbose(fn.name, packageId(pkg))
fn(pkg, folder, parent, gtop, cb)
},
cb
)
})
}
As found here: https://github.com/npm/npm/blob/master/lib/build.js#L93
As you can see here, the comment about the parent
variableclearly points out, that only packages installed in the "root" node modules folder will be linked globally and all others will be linked in .bin
of the packages folder.
To clarify that behavior, I going to give you quick example.
So the structure after I ran npm install -g
would be:
/usr/lib/node_modules
| --> npm
| --> gadada
As we can see, npm has created a new subfolder call gadada
which is the name I have given in my package json. In there the dependencies placed and links are created within /usr/lib/node_modules/gadada/.bin
.
This is because when the depdencies are built, npm check which parent folder they have. If it is not /usr/lib/node_modules
, it would not get linked globally.
For comparison, the outcome of me running npm install -g bower@latest
now, would produce this folder structure:
/usr/lib/node_modules
| --> npm
| --> gadada
| --> bower
At installation npm would realize the parent folder of bower
is /usr/lib/node_modules
and links globally.
This is the whole voodoo behind it. I have not found any site explaining this particular behavior, but I guess it is to prevent dependencies messing with global installations of binaries.
Just for clarification: You global folder for node modules can differ.
/usr/
is just my prefix.
I tried to solve this problem by using `scripts. I found a great tutorial about it, but lost it due to private browsing :/
I suggested to include the commands you need in the scripts
section of your package.json
like this:
{
"name": "gadada",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"bower": "bower"
},
"author": "me",
"dependencies": {
"bower": "latest",
},
"devDependencies": {
}
}
Before you scream: Nooo, what the hell, the full path is missing, consider this.
When you run a command from the scripts with npm run bower
, npm includes the .bin
folder of your $PATH, so that the binaries can be found.
Magic at its finest :)
I hope I could help some people who stumble across the same problem :)
Upvotes: 3
Reputation: 11990
If you mean you are trying to install the dependencies in package.json
globally with npm install -g
...that's not how it works. package.json
is specifically and only used to define locally installed packages. It's the manifest of required modules that can ride along with a project, allowing the total project size to be smaller in transit (i.e. you don't have to include node_modules
in your repo, etc).
The -g
flag is for individually installed global packages, typically for things like command line utilities. While your situation wouldn't really have any serious issues if every module in the project were installed globally, in other cases such a situation would be a Bad Thing.
So you aren't doing anything wrong, it's just not how npm works for installs.
However, you can use the npm scripts to define a pre-install or post-install step that would essentially run a -g
install. This is extra work, but if you own the project and you're going to be doing this alot...it could be a nice way to automate things.
Upvotes: 0