Nvm: Autotomatic reinstall-packages across node versions

Created on 21 Jan 2016  路  20Comments  路  Source: nvm-sh/nvm

This is a convenience feature request, so I understand if there's not an easy way to implement...

I find myself constantly having to use reinstall-packages across different versions. Especially when I add a global module to one version of node and forget to add it to others. Is there a way to have npm install -g apply across multiple node versions managed by nvm? Perhaps there could be an .nvmrc option to enable?

feature requests

Most helpful comment

It's a very bad idea to share global modules across node versions for a lot of reasons. However, when installing, I typically do nvm install 0.12 --reinstall-packages-from=0.10 or similar, which does it as part of the install.

All 20 comments

It's a very bad idea to share global modules across node versions for a lot of reasons. However, when installing, I typically do nvm install 0.12 --reinstall-packages-from=0.10 or similar, which does it as part of the install.

Yeah, I wouldn't want the same module shared across multiple versions of node...

What about having an nvm install command that would run npm install -g <module> across all installed versions of node? Or perhaps I could specify which versions to install in. Something like nvm install-package <module> or nvm install-package <module1> <module2>.

The use case would be when you actively use multiple versions of node and want to add a global module to all of them at once.

What I would build for that is a command like nvm exec, called say nvm exec-all, that took a command (like npm install -g foo), and ran it in parallel across every installed node version. However, that seems pretty complex to get right.

When I run nvm reinstall-packages <version> or nvm install <new-version> --reinstall-packages-from=<old-version>, I run into the EACCES error I would get if I weren't using nvm and didn't use sudo. Since nvm allows me to not use sudo when I do a normal npm install -g <module>, why do I no longer have permission to install global packages when I use nvm reinstall-packages? Is there any way to use nvm reinstall-packages without changing the permissions on my computer? I tried sudo nvm reinstall-packages <version>, but I just get sudo: nvm: command not found. Is there a simple fix to allow nvm reinstall-packages to work the way running npm install -g <module> works without sudo when using nvm?

is there a chance you originally installed some of those global modules with sudo npm install -g such that the permissions are messed up?

@ljharb
It's possible that a few of my global modules were installed that way because when I first started using nvm, I wasn't aware that I didn't need to use sudo anymore, so I ended up installing a few modules with it. I'll try uninstalling them and re-installing them without sudo. Thanks!

@LiuJoyceC thanks, if you find you still have problems please file a new issue and I'll see what I can do!

Why not introduce logic that decides to place all Node < 5 global packages into one directory, and all packages into another directory when using 5.0+?

nvm use 4.2.2
npm i -g gulp
#=> ~/.nvm/versions/node.-5/node_modules/gulp
#=> ~/.nvm/versions/node/v4.2.2/lib/node_modules/gulp is available
#==> because the entire 'node.-5/node_modules' dir has already been symlink'd to '4.2.2'

nvm use 6.1
npm i -g gulp
#=> ~/.nvm/versions/node.+5/node_modules/gulp
#=> ~/.nvm/versions/node/v6.1.0/lib/node_modules/gulp is available
#==> because the entire 'node.+5/node_modules' dir has already been symlink'd to '6.1.0'

Now, when installing a new version, you can run the same logic to check if the target version is above or below 5.0. Whatever it is, create symlinks from the shared dependency folder (node.-5 or node.+5) to the version's specific folder.

nvm install 5.4.1
# 5.4.1 is > 5.0 ~> use 'node.+5'
# run installation
# symlink '~/.nvm/versions/node.+5/node_modules' to '~/.nvm/versions/node/v5.4.1/lib/node_modules'

Lastly, using reinstall-packages will (1) drop the current version's symlinks, (2) re-map the shared folder's modules as a symlink, (3) actually install any missing dependencies to the shared directory, and, possibly, (4) re-map the newly installed packages.

Note: I often do exactly this for local (per project) development whenever I am traveling and stable internet connections are sparse.

@lukeed what would be the benefit of that? Global packages might work on node 5 but not 6, or vice versa, etc. "before 5" and "after 5" are useless and meaningless distinctions.

In addition, you'd need npm rebuild to recompile for the right node version, and then that would break the use case of "two shells with different node versions being used simultaneously".

So far, I've found that everything working on 5 works on 6.

And the distinction is not meaningless. Post-5.0, all modules are installed shallowly so that the node_modules directory is one level deep. Node 4 and below, this was not the case. When you installed gulp, your the only new addition to node_modules is a gulp directory. With Node 5+ install, gulp and all its sub-dependencies are added as first-level children of the node_modules folder.

And you do not need to rebuild. The symlinks stay & act as if the packages are installed directly to/for that version. To your OS, there's no difference between this setup and the _current_ setup.

@lukeed that's both not true (there's plenty of modules that work on 5 but not 6) but also won't be true when 7 comes out, or 8, etc.

It's not "post-5.0", it's "with npm 3" - and you're also not correct. It's not that node_modules is flat - it's _absolutely not_ - it's that absent version conflicts, it will be flat. If there's version conflicts in the tree, it definitely won't be flat. Relying on node_modules being 1 level deep is utterly broken.

I'm not sure how to explain it any better - but compiled modules must be rebuilt for each platform _and node version_, every time one of those changes. This is a fact.

@ljharb Welp, perhaps the explanation & wording aren't right... but the setup is working for me locally right now, with two tabs open to two different versions... Proof below.

Slicing the "shared" directories into narrower chunks is, _of course_, a better way to go. All that seems to matter is that the node_modules tree is as expected.

And obviously the modules tree isn't flat. 馃檯 ^That was just a quink-n-very-dirty reason why 卤5 was chosen.

Proof

screen shot 2016-06-29 at 8 54 53 pm
screen shot 2016-06-29 at 9 07 20 pm
screen shot 2016-06-29 at 9 12 14 pm

I used 5.0, 5.4, and 5.5 as my throw-away testers. All their node_modules and bin scripts have been moved to ~/.nvm/versions/shared/5/{bin,node_modules}. That said, you (of course) need to retain each version's actual npm (module and bin) and node (bin). Everything else is symlink'd in from the shared directory.

In this way, each version thinks it owns its own unique copy while, in reality, the dependencies are truly shared across all installations, without the need to rebuild or reinstall any dependencies upon switching versions. 馃帀

From here, all that's left is to automate the installation, as described before.

@lukeed that is a fine solution for when you understand the constraints and are willing to accept the consequences - but there's no way it would work in a generic sense for all of nvm's use cases.

Rather than installing global modules from an existing node version or sharing global modules between versions, it might be more simple and useful to have a post install hook to install a set of global modules that are regularly used.

Perhaps nvm install could just check for a NVM_POSTINSTALL env variable, then in my .bash_profile I could have

export NVM_DIR="$HOME/.nvm"
export NVM_POSTINSTALL="npm install -g serve webpack standard"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm

I regularly update node and I think this fairly harmless change would save a lot of time. A more opinionated way might be nice in future, for example an env variable list of node modules NVM_GLOBAL_MODULES but I feel like that would encourage a much larger debate.

I'd be happy to put together a PR for this change...

@roberttod big thumb up for that.

@roberttod that's not a bad idea. I'd be happy to review a PR (with no promises for acceptance) if someone wanted to write one.

n package manager implements common global npm packages.

@sandrodz ok, but it shouldn't. Global npm packages should never be shared across node versions or architectures.

@ljharb yep, that's why I opened this issue: https://github.com/tj/n/issues/405

It seems like #1463 (merged but not yet released) covers this use case.

@tribou, happy to reopen if you disagree!

Was this page helpful?
0 / 5 - 0 ratings