-
-
Notifications
You must be signed in to change notification settings - Fork 8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Npm global modules #668
Comments
Thanks to this thread, I just realized that what I suggested can be achieved by adding this line to export NPM_CONFIG_PREFIX="/usr/local"` Closing this issue :) |
Please don't do this, however - you absolutely do not want to share global modules across node versions, as that can cause incompatibilities. Use |
More to the point, in a future version, |
With the rapid releases of io.js, does it make sense to add this to the README? |
@ljharb I completely disagree. Let the user have this option and decide for him/her self. In my case global packages are just a few shared tools, and reinstalling/updating them each time in different places would be a total nightmare. Single project packages must be locally installed instead, and that avoids any compatibility problem already. I see your concerns, but forcing users to do things they absolutely don't want is an arguable principle in software design. Rather trying to understand what they need, and how it could be achieved in a more convenient way might be helpful. In case it's useful to have a concrete example, here's a list of npm modules I have globally installed right now:
I often need to switch between node stable and iojs, and regularly update both pieces of software as new versions come out. Imagine the nightmare of re-installing and updating all these npm modules in many different places each time, having to check if they're available and what version I'm using. That to me seems the exact opposite of "global", besides being a huge waste of time and completely unpractical. |
@pensierinmusica many native modules do not work between versions of node, like I think this is the main rationale behind maintaining separate global modules between versions. |
@pensierinmusica I think I have changed my mind somewhat - I won't have |
@ljharb thanks for sharing the shortcut to reinstall packages across different Node versions. I also agree that showing the user a message on how to fix incompatible settings is a good approach! Cheers I think it would be very interesting also to give the user an option when it installs or updates a global npm module to be able to perform the same operation for all available node versions on the system. Imagine something like Thoughts? |
Not every node version can have the latest npm - try it in node I could see a |
Thanks! PS - I also agree with your decision to not invasively configure things on the user's machine. That said, a message informing them of their unwise decision would be welcome :) |
Closing this - global modules should never be shared across different node versions. |
I'd like to see this re-opened. For the reasons mentioned above, having software you happened to install with I'd like to posit that I'm not a complete idiot, but this ‘feature’ literally bites me in the ass monthly. I've been aware how Here's my solution to the problems listed above:
I realize this may be controversial, but I think it's a really serious failing of |
By installing The only way this would work safely is if |
It's one thing with something like Here's another way to look at it: by its very nature, |
You make a very strong argument. However, the fact remains: If I install If, after switching to Typically what I do is have a system node installed, and install global packages there, and then do not install them on |
@ELLIOTTCABLE Just create a quick function in your function nvm-install {
nvm install $1 --reinstall-packages-from=default
} If your default node/iojs install is where your global modules are, then you never have to remember to include the flag again. Just start using your bash function. Example:
The above would install node v0.10.33 and copy all the global modules from the default version. |
@ljharb hm; you're definitely right about ‘continuing to use the Node it was installed with’ being an even more intuitive approach. Two things:
@chevex that's a good start; @ljharb is there any ‘hook’ system in |
There's not a hook system really - there's lots of internal functions, but it's dangerous to rely on those, and there's lots of functionality in the raw |
You could also modify the bash function I suggested to literally symlink the global node_modules directories in newly installed versions. Then you'd transparently be pointing at the same global modules directory as the default install. You'd even be able to install new modules or update existing modules no matter which version you are using, and they'd all end up in the same place. |
There's a lot to digest in this thread, I'm definitely missing details on use of I've installed nvm primarily to alleviate permissions issues with I'd already done a
.. which gets me back to a shiny, familiar state.. many tx This was good reading, too: https://groups.google.com/d/msg/nodejs/A9ku09F39-k/PkYynJOCmrIJ |
@ptim a PR to enhance the read me is always appreciated ;-) |
So this doesn't really matters for modules as the title says, but, AIUI, for scripts in .../bin. Which is what I encountered within 30 minutes of installing nvm 😉 My homebrew solution was to replace the global scripts with wrapper scripts: https://gist.github.com/lalomartins/e04317bd953f954bb0a1 How about baking this feature into nvm? I'm not sure whether it should be automatic or manual, though. Automatic could work like:
Manual is a little less tricky — |
The best is If it's not installed for the current version, it shouldn't be run - it should be installed, perhaps, but that's it. |
I think you have an UX design problem there :-) Think from the user point of view. Something like bower or cake is in no way part of a node version, and it shouldn't be; treating it as if it were breaks it for no good reason. It's an app that just happens to have been installed with npm. Also, I doubt we'll convince people to type An alternative is to make this a completely separate subsystem in nvm; something like |
… then it would be conceivable to print a warning if you install anything globally while in a nvm version. “Scripts installed with npm -g will only be available in the current version of node; if you meant to use them as a system app, install them with nvm install-app instead.” |
Personally though, I think it's redundant to make it a separate subsystem, since according to the npm faq the only time you should use install -g is for apps: https://docs.npmjs.com/getting-started/installing-npm-packages-globally
|
In this case the user is a developer, so a higher bar may be assumed. Global modules are absolutely part of a node version, and it's a mistake to think about them otherwise. I'll still think about how this might be resolved though. |
Well, rather think about whether “Global modules are absolutely part of a node version, and it's a mistake to think about them otherwise”. Sleep on it maybe. Since your absolutely is different than my obviously, considering my argument is the least courtesy you can extend, rather than mashing a reply in less than a minute. |
Bear in mind the npm faq pretty much agrees with me… |
The npm faq is written assuming you have a single node version installed, so it's irrelevant here. |
The problem is you're thinking in terms (and the issue title refers to) “global modules”. In real-life node usage (and npm best practises), there's no such a thing as a global module, only a global app. Yes you can use those as a global module by fiddling with NODE_PATH, but that's recommended against. |
This may be some people's real-life node usage, but it is NOT mine, and it is not most nvm users'. In addition, there are no "npm best practices" here since npm's guide is irrelevant in a multiple-node situation. I'd certainly prefer to make using |
¯_(ツ)_/¯ |
When you run a "global app" it runs a shebang script where the first line tells it to run "node" or "iojs". Your shell will then look in your PATH and find an executable for node or iojs, run it, and pass in the rest of the script to be interpreted. At no point in this process is it able to reach out to nvm, figure out what version of node/iojs is installed, download the correct package for that version and run the exact needed engine or "app". It uses whatever version you currently have installed. As @ljharb explained, npm is not built to understand a multi-install environment. If you upgrade node and suddenly a "global app" stops working then your only solution is to downgrade node to a supported version or upgrade the "app" to a version that supports the version of node you have installed. If you use nvm to install multiple versions of node/iojs then it makes it easy to install a "global app" under one version and then later try to use it under another version. If nvm allowed this to happen it could cause it to break, or worse, run with unexpected side effects. There's no way for the shebang script for the "global app" to fire up the right version of node/iojs without some complex communication between bash and nvm. Bash would have to know what versions of node are installed and where. All nvm does is swap out which version of node/iojs is in your path so that bash can operate as it already expects to. It's not nvm's responsibility to magically make things work in different versions of node/iojs as you switch them around. Trying to run scripts under engines that the script does not say it supports shouldn't be taken lightly because the side effects of running code in outdated engines or engines that are too new can be very unpredictable. You also can't just be swapping out your node/iojs version automatically whenever you want because you could be doing it underneath a running process that may potentially call into it again, say, to spin up child processes and whatnot. Now if nvm functionality were baked into npm itself then I could see this discussion having a lot more merit because node and npm could work together to help scripts that are dependent upon a specific version of node, fire up the right engine during runtime. Nvm isn't part of npm though, and so must try to stay as hands-off as possible, letting node & npm operate as they normally would without ever having to be aware other versions are being swapped in at will. The best way to do that is to keep global modules compartmentalized with the proper node versions, and to make version switching be a manual user-intended operation. No automatic switching or version-agnostic globalizing just to make a single task slightly less inconvenient. |
NVM is fantastic, but this is the single issue I have every time I upgrade even a dot version of Node. I usually run What is the final conclusion in this thread? Do we really have to resort to workarounds like custom functions in our bash profiles etc? Does Thanks. |
@arcseldon |
@ljharb - appreciate the confirmation, thanks very much. I will make sure my Clients using Node are also aware of this. |
Maybe my tool could help people a little: https://github.com/bahmutov/all-nvm - runs the same command (including install) across all Node versions managed by NVM |
@bahmutov if it's npm-installed that would install it in one of the nvm-managed node versions - that doesn't make any sense to me. |
@ljharb the original post lamented the lack of "global" tools when using NVM. My tool solves this problem by installing the same tool in each, while avoiding shared / global installation problem that people were upset about in this thread. |
I solved this with a small script that uses some nvm core functions. It upgrades nodejs to the latest version whilst migrating all global modules. Afterwards it updates every global npm package to "latest" as an added benefit. # node_updater.sh
#
# This script makes keeping NVM-managed NodeJS and its global packages up-to-date a breeze.
# Requires nvm, the Node Version Manager (https://github.com/creationix/nvm)
#
# First load it: _$: touch node_updater.sh
# Then run it: node_updater
#
# Protip: Add to your .bash_profile for hassle-free updating.
#
node_updater () {
export NODE_CURRENT=$(nvm_ls_current)
export NODE_LATEST=$(nvm_remote_versions | grep '^v' | tail -1)
# Update global NodeJS to 'latest'. Migrates all installed global packages into the new Version.
echo "Updating global NodeJS installation from ${NODE_CURRENT} to ${NODE_LATEST}."
nvm install ${NODE_LATEST} --reinstall-packages-from=${NODE_CURRENT} && echo "Upgrade of global NodeJS installation complete."
# Remove previous NodeJS versions
nvm use ${NODE_LATEST}
# Update global NodeJS packages to 'latest'
for PACKAGE in $(npm --global outdated --parseable --depth=0 --loglevel silent | cut -d: -f3 | cut -f1 -d'@');
do npm --global install --loglevel silent ${PACKAGE} && echo "Updated global package '${PACKAGE}' to 'latest'.";
done
# Uncomment to delete previous NodeJS installations after update
#find ${NVM_DIR}/versions/node -type d -mindepth 1 -maxdepth 1 -not -name ${NODE_LATEST} -exec sh -c 'printf "Removed NodeJS version: "' \; -exec basename {} \; -exec rm -r {} \;
} Gist @ https://gist.github.com/sidneys/e27eb239fd022d3e5204 |
Thanks @sidneys, looks cool :) The only part I'm not 100% convinced about is: # Remove previous NodeJS versions
nvm use ${NODE_LATEST} Would it make sense to change it with this? # Update "default" alias and switch to it
nvm alias default ${NODE_LATEST}
nvm use default Cheers! |
For everyone interested.. I've made a little tool for this: npmg. It stores a list of packages that you want installed globally, and when you end up in a new environment (like a different node version) you can run |
That's amazing! Unfortunately it doesn't work for me though 😢 I've added a package to that file, installed a new version of node, and that package isn't installed. Ah well, will take a look at it some other time. |
@Jpunt make sure you’ve updated to the latest version of nvm. |
Npm saves global modules where Node is installed.
This is unconvenient when there are multiple versions of Node on the system, and one needs some npm modules globally available (afterall, that's the concept of "global", isn't it?)
For the same reason, in the current setup global modules get lost each time a new version of Node is installed.
Think about modules like Yeoman (and its generators), Grunt, Express, and so on.
Wouldn't it be way more convenient if we could keep global npm modules in a common folder in the system (something like
/usr/local/lib/node_modules
), that can be accessed by all Node versions?This way it's easier to install, uninstall, or update things just once and have the same setting system-wide. If a project needs something different, then the module should be installed locally (like it happens for most modules).
It just seem to make much more sense to me, besides being more efficient.
Is there a way for nvm to implement this? What are your thoughts?
Cheers!
Alex
The text was updated successfully, but these errors were encountered: