Nvm-windows: Support .nvmrc

Created on 8 Jan 2016  Â·  18Comments  Â·  Source: coreybutler/nvm-windows

Alows project to speicify the version to be used.
See nvm usage

or perhaps parse closet available version from package.json engines

enhancement request wontfix

Most helpful comment

The .nvmrc support is a fairly important aspect of using NVM with a CI system. I don't link the package.json suggestion, especially as it breaks compatibility with nvm, but would a pull request with support for .nvmrc be accepted?

All 18 comments

I don't think this is a route I want to go down. The primary reason is it would require some very ugly hacking to recreate/mimic the node binary. For example, calling node index.js means the hacked/faked node.exe would need to first parse the package.json file (if it even exists) to determine the version and then execute the real node.exe for the appropriate version.

Some other similar projects have attempted to use .bat files to accomplish this. This approach is fragile, and it goes against the primary objective of the architecture.

I also just don't think the demand is widespread for this.

The .nvmrc support is a fairly important aspect of using NVM with a CI system. I don't link the package.json suggestion, especially as it breaks compatibility with nvm, but would a pull request with support for .nvmrc be accepted?

@gruber76 - I probably won't accept a PR on this.

.nvmrc, package.json... they both require the same nasty hack.

@coreybutler I'm not sure I understand your rationale for not wanting to support this. Wouldn't having this feature simply fallback to looking into the .nvmrc file whenever nvm is invoked without specifying a version number? Hence, what nasty hacks are you talking about?

The nasty hack: rewrite symlinks for Windows.

NVM for Windows works by changing the symlink target to the desired physical node installation directory. This is a system-wide change.

Let's say you fire up a script by specifying version 0.12.0 in a .nvmrc file, then fire up a second script without a .nvmrc. The symlink would point to v0.12.0 (from the first instantiation). If the 2nd script requires something else (like v4.2.6) with no .nvmrc, it will fail. This introduces environment instability when using symlinks because there is no true process isolation.

The only way to truly isolate a version on a per-process basis is to have nvm.exe redirect to the version the script is requesting instead of allowing the operating system to do it. I really don't want to recreate something the operating system already does for us.

If people really want to use a per-process/project approach, a more appropriate solution is isolating the runtime environment. Personally, I use Docker for that.

Forgive me for my ignorance, here. My primary use case is developing node/web applications using bower/grunt/gulp, etc. with multiple teams. For me, it is extremely rare that I would have multiple versions running within five minutes of each other. For this use case, the .nvmrc file is how my teams specify what node should be doing.

I'm having trouble seeing in the situation you describe (script A versus script B) how supporting .nvmrc would be any more troublesome than having script A (or a user of script A) calling nvm to set the version and then forgetting to set it before running script B. But I'm guessing there are some common use cases for nvm that are much harder core than mine. Possibly, for instance, if my CI servers had a heavier load.

I do have a hackey workaround to offer up to anyone else who needs it. The following in a pre-run bat script:

set /p nodev=<.nvmrc
nvm install %nodev%
nvm use %nodev%

Why not put the nvm command to set the required version in a npm script?

Steve Lee
Sent from my mobile device Please excuse typing errors
On 3 Mar 2016 16:50, "gruber76" [email protected] wrote:

Forgive me for my ignorance, here. My primary use case is developing
node/web applications using bower/grunt/gulp, etc. with multiple teams. For
me, it is extremely rare that I would have multiple versions running within
five minutes of each other. For this use case, the .nvmrc file is how my
teams specify what node should be doing.

I'm having trouble seeing in the situation you describe (script A versus
script B) how supporting .nvmrc would be any more troublesome than having
script A (or a user of script A) calling nvm to set the version and then
forgetting to set it before running script B. But I'm guessing there are
some common use cases for nvm that are much harder core than mine.
Possibly, for instance, if my CI servers had a heavier load.

I do have a hackey workaround to offer up to anyone else who needs it. The
following in a pre-run bat script:

set /p nodev=<.nvmrc
nvm install %nodev%
nvm use %nodev%

—
Reply to this email directly or view it on GitHub
https://github.com/coreybutler/nvm-windows/issues/128#issuecomment-191852401
.

Supporting the .nvmrc file would be really helpful. We have many projects, and they don't all run the same version of node. The .nvmrc file is at the root of each repo to ensure that the correct version of node is being used for a given project.

As a side note, it's also kind of annoying that nvm install must be followed by nvm use. I'm curious to know the reasoning behind requiring the second step after an install. I can see how installing and using are different things, but I wonder if there is ever a use case where someone would download and install, but not use.

Our work-around for this is that we have a file named install-node.js that lives at the root of each project. Whenever we switch to a project, we run node install-node from the command line. The contents of the install-node.js file are as follows:

var childProcess = require('child_process')
var fs = require('fs')

var nodeVersion = fs.readFileSync('.nvmrc', 'utf8').trim()

var command = "nvm install " + nodeVersion + " && nvm use " + nodeVersion
console.log('executing command: ' + command)
childProcess.exec(command, function(error, stdout, stderr) {
  if (stdout) console.log(stdout.toString())
  if (stderr) console.error(stderr.toString())
  if (error) console.error(error)
})

@josh-egan-ps - The separation between install and use was mostly for mass environment configuration. I will often install several versions of node before flipping between them. However; it seems perfectly reasonable to have a flag, like nvm install -u 5.9.1 to install and automatically use... or automatically use the version and have a flag to _not_ use it. I'll definitely consider adding this.

For everyone - If you really need to switch on a per-project basis, consider putting nvm use x.x.x && node index.js in the npm start script section of your package.json. A common best practice is to always use npm start to launch a node app.

For everyone - If you really need to switch on a per-project basis, consider putting nvm use x.x.x && node index.js in the npm start script section of your package.json. A common best practice is to always use npm start to launch a node app.

That might actually be too late in the case any npm _build_ scripts used during install that depend on node / npm version. Or other tools such as grunt etc run expicitly They could fail during install with the wrong version of node / npm. or use the wrong version causing other problems, BTW I'm assuming the other best practice of having _everything_ locally installed (ie not -g) so version dependencies are never a problem.

Thus it's good practice to use the npm install to setup every thing. You can then add a preinstall step to use nvm use. eg add

    "preinstall": "nvm use x.x.x",

That should be OK even if the original npm version will be running in the parent process. The install step will launch a new shell so all actions should pick up the new node and npm.

You might even want to add a pre start step than installs.

@SteveALee - yeah, you're right, my earlier suggestion wouldn't work. It would be too late in the process to launch reliably.

@coreybutler In the end I went for this

"preinstall":"nvm use 4.4.1 || echo nvm not found: check node version && pause",

Perhaps a nvm use -i x.x.x option would be good? That is, install if not already there?

I would like to suggest to implement a part of this at least:

On Linux / Mac, in a folder with a .nvmrc file present, I can run nvm use without specifying a concrete version, and the installed version that matches the content of .nvmrc gets activated. If the file says 8, then the latest installed version of Node 8 gets installed.

I combine this on my systems with a script that overloads cd so that I can cd into a directory and the right version of node gets activated, with this script in .bashrc:

# Support .nvmrc
load-nvmrc() {
  if [[ -f .nvmrc && -r .nvmrc ]]; then
    nvm use
  elif [[ $(nvm version) != $(nvm version default)  ]]; then
    echo "Reverting to nvm default version"
    nvm use default
  fi
}
# Override `cd` to auto-load correct version of Node on enterting directory.
cd() { builtin cd "$@"; 'load-nvmrc'; }

This could easily work on Windows too, if nvm was respecting these files.

A .nvmrc won't be implemented by default. However; the roadmap has a plan for hook support (https://github.com/coreybutler/nvm-windows/issues/190). A pre-use script could be used to adjust the version according to any file they want (including package.json, .nvmrc, or anything else you choose).

Since this issues seems to be nearly dead, I've got a workaround Powershell script that should mimic the functionality of "nvm use" and "nvm install" if the .nvmrc file contains a single digit node version.

nvm install (Get-Content .nvmrc) would work fine however nvm use (Get-Content .nvmrc) won't work (because when a single digit version is passed to install, it installs the most recent revision of that node version but nvm use with a single digit appends '.0.0' to it instead of getting the most recent.

@coreybutler If you updated the "use" command in nvm.go to use the same code as install, it would make this fix unnecessary (i.e.):
if len(version) == 1 { version = findLatestSubVersion(version) } else { version = cleanVersion(version) }

The following script will use "nvm list available" and filter the list for the highest LTS version that matches the .nvmrc file's version and then 'nvm use' it. If it is not installed, it 'nvm install's it then 'nvm use' it.
((nvm use (nvm list available | Where-Object -FilterScript { $_ -like ('* ' + (Get-Content .nvmrc)) + '.*'})[0].split('|')[2].trim()) -like '*not installed*') -and (nvm install (nvm list available | Where-Object -FilterScript { $_ -like ('* ' + (Get-Content .nvmrc) + '.*') })[0].split('|')[2]) -and (nvm use (nvm list available | Where-Object -FilterScript { $_ -like ('* ' + (Get-Content .nvmrc) + '.*') })[0].split('|')[2].trim())

Just want to request the support of nvm use to read from an .nvmrc file. It would really make my node development experience between Mac and Windows to be seamless.

Is this closed because it was fixed or is not going to be changed?

Is there another Windows-compatible version of nvm which uses the same API as the *nix versions?

Was this page helpful?
0 / 5 - 0 ratings