nvm-sh / nvm

Node Version Manager - POSIX-compliant bash script to manage multiple active node.js versions
MIT License
77.91k stars 7.8k forks source link

Honor .node-version file #794

Open mnquintana opened 8 years ago

mnquintana commented 8 years ago

Forgive me if this has been discussed before, but I didn't find anything beyond https://github.com/creationix/nvm/issues/110#issuecomment-40525629.

It would be really nice to see the various Node version managing tools coalesce around a common "version config file", analogous to Ruby's .ruby-version for RVM and rbenv - .node-version. This would basically just be an alias for .nvmrc, since that functionality's already been added. Since n already supports .node-version, this would make it so that regardless of the Node version manager used, there could be some degree of guarantee that the correct version will be used.

ljharb commented 8 years ago

When did n add support for node-version?

Which would win if you had both files present?

What about the different version formats that nvm supports - ie, iojs, stable, node, or 0.10, etc - and how do other version managers interact with those? What special formats do they offer that nvm might be forced to interact with?

mnquintana commented 8 years ago

When did n add support for node-version?

Ah sorry, my mistake, it wasn't n - it's avn and nodenv. I actually asked the Stack Overflow question about this awhile back.

Which would win if you had both files present?

I think I'd expect .nvmrc to win if both files were present, but I don't really have strong feelings about this.

What about the different version formats that nvm supports - ie, iojs, stable, node, or 0.10, etc - and how do other version managers interact with those? What special formats do they offer that nvm might be forced to interact with?

That's a good question - I'll have to research this a bit.

ljharb commented 8 years ago

I'd never heard of nodenv, but avn alone isn't enough for it to be a "common" version file. Do note my answer on that question which I think is a bit better than the accepted one http://stackoverflow.com/a/29545541 :-)

mcandre commented 8 years ago

+1

Rapid, per-project .ruby-version switching with rvm is too useful not to have this for Node.js!

lpil commented 8 years ago

:+1:

Ajedi32 commented 8 years ago

I think the idea here is that even though .nvmrc already provides this functionality, having a more generic cross-implementation .node-version file would be beneficial.

As @ljharb pointed out though, interoperability here would require more than just a common filename. iojs, stable, node are also valid version numbers for nvm, but not necessarily for other implementations. I'm honestly not sure how that should be handled. Maybe some discussion with the maintainers of other node versioning-type projects is in order...

ljharb commented 8 years ago

If all of nave, n, avn, and whoever else all wants to cleave to nvms "version-ish" format, or, at least is prepared to accept or reject it gracefully (for example, supporting a version number but not a generic tag), that's great. Note that soon I'll have release candidate support for io.js and node, and these will have a different prefix as well, and who knows what the future will bring?

lalitkapoor commented 8 years ago

Just for .nvmrc files - https://github.com/lalitkapoor/nvm-auto-switch - I appreciate any feedback. Thanks!

ljharb commented 8 years ago

Please use github reactions on the original post rather than posting "+1". Fair warning, I'll clean up existing and future comments that simply say that.

paulodiovani commented 8 years ago

If all of nave, n, avn, and whoever else all wants to cleave to nvms "version-ish" format, or, at least is prepared to accept or reject it gracefully (for example, supporting a version number but not a generic tag), that's great.

That's not a problem, at all...

nvm could use .node-version as an alternative, but still giving preference to .nvmrc.

Project owners could decide to use a wider syntax on .node-version (just the version number, which, I think, it's most of cases) to allow use of any version manager OR use a specialized syntax and prefix on .nvmrc.

I don't even think nvm should care about which file is in use, but just parse .nvmrc or .node-version (in this order).

epixa commented 7 years ago

I'm not sure if I even like this idea, but a generic approach to "supporting" node-version directly might be to support a syntax in nvmrc that allows people to read the version string from any other file.

// .nvmrc
file:.node-version

// .node-version
6.3.1

This approach does have some pleasant side effects:

  1. No chasing additional version "standards" once the precedent has been set by supporting .node-version
  2. No questions of precedence
  3. No need to hardcode any subtle differences in support between the two standards since you're essentially making the assumption that the other file is compatible with nvm rather than the other way around.
ljharb commented 7 years ago

That's not a half-bad idea. However, file:.node-version is a valid alias name, so it'd probably have to be something with a slash in it.

I'll think about that one more.

TylerBre commented 7 years ago

.node-version is a much more sane name than .nvmrc

furthermore, I don't see why it shouldn't support both

ljharb commented 7 years ago

@TylerBre please don't use ableist terms like "sane".

node-version would work if it was a universal version identifier. However, nvm supports io.js, and aliases, neither of which are necessarily "node" or "universal".

koenpunt commented 7 years ago

Even though nvm support io.js, .node-version would still be relevant. And to be fair, nvm stands for "node version manager", and io.js isn't node, it's node compatible. That being said, I think it should be possible to honour .node-version for node versions, and maybe then also support .iojs-version, if that's still relevant for someone.

ljharb commented 7 years ago

io.js is node, versions 1-3, after the fact.

You're also missing the most important part, which is "aliases".

koenpunt commented 7 years ago

The purpose of .node-version is that you want a static, consistent version. Specifying an alias would defy that purpose.

ljharb commented 7 years ago

I agree - which would mean that nvm respecting node-version would have to be limited to static versions only.

What do avn and nodenv support in node-version files? If it's just "a static version, with or without a leading v" then the possibility still remains open that nvm could support that too.

koenpunt commented 7 years ago

nodenv differentiates between node and iojs with definitions like 0.10.36 and iojs-1.0.0 (as seen in their README). And it requires that exact version to be installed. Installing of that version can be done by running nodenv install (with the node-build plugin added).

ljharb commented 7 years ago

Does nodenv work if you do have a v prefix? (does rvm support the v in .ruby-version?)

koenpunt commented 7 years ago

My assumption was it wouldn't work with the v prefix, but it does:

$ cat .node-version
v5.12.0
$ nodenv version
5.12.0 (set by /Users/koenpunt/.../.node-version)

rvm I don't know, but rbenv does, as is about the same as nodenv (nodenv is a port of rbenv)

ljharb commented 7 years ago

That's encouraging - it means we could support v1.2.3 or 1.2.3. I'm hesitant to include the "iojs-" prefix, though, since there's no overlap with node - unless every other node version management tool supported it too.

Either way I've filed https://github.com/nodejs/version-management/issues/13, and I think this issue should be blocked on that.

philsturgeon commented 6 years ago

I just swung by to leave an issue and see if there was any interest in this, but looks like there is!

RVM and rbenv both have their own files and formats but both agree on .ruby-version, and it would be lovely if nvm and nodenv could agree on a common file too, even if nothing changes by default.

Here's how RVM load the file:

.rvmrc - shell script allowing full customization of the environment, .versions.conf - key=value configuration file .ruby-version - single line ruby-version only Gemfile - comment: #ruby=1.9.3 and directive: ruby "1.9.3"

So, we could very easily add another function to check for .node-version if there is no .nvmrc, agreed?

philsturgeon commented 6 years ago

Here you go! https://github.com/creationix/nvm/pull/1625

franciscolourenco commented 6 years ago

I'd never heard of nodenv, but avn alone isn't enough for it to be a "common" version file.

fnm also supports .node-version

https://github.com/fisherman/fnm/blob/503b07d3b419908409373699c227c4baf32b4b7b/functions/__fnm_read_fnmrc.fish#L4

dmil commented 4 years ago

+1 would love this, colleagues and I use different version managers - the support will help keep us in sync.

cmitz commented 4 years ago

.node-version is also supported by the nodejs plugin for ASDF, a universal version manager (nodejs, ruby, etc etc)

brunolm commented 3 years ago

nvs also supports .node-version

it's kinda annoying needing to have 2 files because different people have different preferences.

JamesMGreene commented 2 years ago

This repo offers a pretty comprehensive growing list of the version managers that honor .node-version: https://github.com/shadowspawn/node-version-usage

Perhaps you could honor both? 🤷🏻‍♂️ Detect .nvmrc first and support more advanced features there but, if that isn't present, detect .node-version and only support its subset of features? 🤔

I know supporting multiple can be a slippery slope but it feels like a reasonable maintenance burden at the moment (to me, as an admitted non-maintainer 😅). ❤️

ljharb commented 2 years ago

Yes, the growing list means it's almost certainly never going to be possible for this specific file to become a standard.

sshaw commented 2 years ago

zOMG 2021 and this shit still doesn't support anything but .nvmrc‽ 🤯

ljharb commented 2 years ago

@sshaw that's a hostile comment, and yes, the date has no bearing on whether there's support for a nonstandard file. we don't support anything right now but our own file, since there's no standard, and that's what every other tool should be doing too.

sshaw commented 2 years ago

@ljharb ... the date has no bearing on whether there's support for a nonstandard file. we don't support anything right now but our own file, since there's no standard, and that's what every other tool should be doing too.

A lack of a standard shouldn't inhibit interoperability especially when other tools i.e., your competitors, have implemented what I think is fair to call "working support" for them and, in some cases on top of their own file.

What is the (edge) case that makes the entire case for supporting .node-version unreliable or, a non-starter due to "lack of standard"?

ljharb commented 2 years ago

Interoperability is only POSSIBLE with a standard. There isn't any such interoperable standard defined for that file.

Some other maintainers may be willing to offer "working support", but I'm unwilling to ship anything that doesn't have full, eternal support.

sshaw commented 2 years ago

Interoperability is only POSSIBLE with a standard.

I've been using asdf and at times nodenv with .nvmrcs for several years. Looks to be pretty operable to me! Maybe I was dreaming? Was curious about the faulty cases. Aliases you mention but the others: who knows!

ljharb commented 2 years ago

I'm very glad your experience has been positive. I do hope you understand that the sum of "anecdotes" is not "data", though, and that what's far more likely is that those who have encountered problems have simply not used that filename to avoid them.

Aliases (user-defined ones; version-manager-defined ones, like nvm's iojs or node; node-defined ones like LTS names or release channel names), fuzzy specifiers (like 14 or 14.1 instead of the fully-qualified version number), to name a few.

alex-latham commented 2 years ago

I added this to my zsh profile to autoload a node version from either .nvmrc or .node-version (with fallback to default if neither found):

# Set node version
function change_node_version() {
  local nvmrc_path="$(pwd)/.nvmrc"
  local node_version_path="$(pwd)/.node-version"
  if [ -f $nvmrc_path ]; then
    echo ".nvmrc file exists."
    version="$(cat "$nvmrc_path")"
    nvm use $version
  elif [ -f $node_version_path ]; then
    echo ".node-version file exists."
    version="$(cat "$node_version_path")"
    nvm use $version
  else
    echo "Neither .nvmrc nor .node-version files exist."
    nvm use default
  fi
}
chpwd_functions+=(change_node_version)
cmolina commented 2 years ago

If you are interested in augmenting the existing function mentioned in the README, I highlighted the lines that you need to copy from @alex-latham's solution:

  load-nvmrc() {
    local node_version="$(nvm version)"
    local nvmrc_path="$(nvm_find_nvmrc)"
+   local node_version_path="$(pwd)/.node-version"

    if [ -n "$nvmrc_path" ]; then
      local nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")

      if [ "$nvmrc_node_version" = "N/A" ]; then
        nvm install
      elif [ "$nvmrc_node_version" != "$node_version" ]; then
        nvm use
      fi
+   elif [ -f $node_version_path ]; then
+     version="$(cat "$node_version_path")"
+     nvm use $version
    elif [ "$node_version" != "$(nvm version default)" ]; then
      echo "Reverting to nvm default version"
      nvm use default
    fi
  }
mcandre commented 2 years ago

I find nodenv[-install] to be highly reliable these days. Wonder if that supports querying desired node version ranges from package.json.

On Tue, Mar 22, 2022, 2:52 PM Carlos Molina A @.***> wrote:

If you are interested in augmenting the existing function mentioned in the README https://github.com/nvm-sh/nvm#zsh, I marked the lines that you need to copy from @alex-latham https://github.com/alex-latham's solution:

load-nvmrc() { local node_version="$(nvm version)" local nvmrc_path="$(nvm_find_nvmrc)"+ local node_version_path="$(pwd)/.node-version"

if [ -n "$nvmrc_path" ]; then
  local nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")

  if [ "$nvmrc_node_version" = "N/A" ]; then
    nvm install
  elif [ "$nvmrc_node_version" != "$node_version" ]; then
    nvm use
  fi+   elif [ -f $node_version_path ]; then+     version="$(cat "$node_version_path")"+     nvm use $version
elif [ "$node_version" != "$(nvm version default)" ]; then
  echo "Reverting to nvm default version"
  nvm use default
fi

}

— Reply to this email directly, view it on GitHub https://github.com/nvm-sh/nvm/issues/794#issuecomment-1075575965, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAABJRBPHXO5HNZPNAF7PD3VBIQIDANCNFSM4BMT6JZA . You are receiving this because you commented.Message ID: @.***>

bilalq commented 2 years ago

@ljharb

Is there any chance at all you would be willing to change your mind here? There is real developer pain caused by nvm's refusal to interop. This schism creates fragmentation pain felt by end users. The problem gets exacerbated further for non-development folks like designers and PMs who may want to try running apps locally and get tripped up when setup docs just say to install any node version manager of your choice. As you'd expect, nvm is the top search result for "node version manager".

I'd argue that .node-version is already a de-facto standard (albeit, with gaps in specification). There is value in adherence to conventions. Markdown had no formal spec and was loaded with ambiguous edge cases, but it's become almost universally accepted. Sure, there are localized flavors of it now, but the commonalities of Markdown still deliver value. Even JSON didn't really have a formal standard till 2013, long after it already had wide usage.

I totally understand your perspective of wanting to only build on solid foundations. My perspective here is that more harm is done by not supporting .node-version. The conventions around .node-version are to support a subset of what .nvmrc supports. Just treating .node-version the same as .nvmrc would address the interop concerns.

If you're dead set against making this default behavior, could you let this work off an env variable?

ljharb commented 2 years ago

@bilalq there's no "refusal" to interop - no interop exists, because there's been no group consensus reached about the specification for the .node-version file.

A defacto standard requires a predominant subset of semantics, which nobody's illustrated exist. Is the "v" prefix required, optional, or forbidden? Is a semver version triple required, or can a major.minor or major be specified? In the latter two cases, is a trailing dot required, optional, or forbidden?

The most POSSIBLE harm is done by implementing a nonstandardized potential standard - and this includes every existing tool that supports this wildly underspecified filename.

shadowspawn commented 2 years ago

The predominant subset of semantics, supported by all utilities I have examined, is:

https://github.com/shadowspawn/node-version-usage

TeoTN commented 2 years ago

I'd recommend following Robustness Principle, and implementing what gives people value, recognising commonly used patterns that may become standardised in the future. Even if there was a standard, according to the robustness principle it would be a good practice if nvm accepted more formats beyond standardised. There's no reason for gatekeeping just because there's no agreed version - unsurprisingly other tools & IDEs found their way to help people, by just implementing what seemed a good judgement of most used values.

robcresswell commented 1 year ago

Hi @ljharb! I wondered if you'd reconsidered your opinion over the past few months at all. I understand your views (though I disagree with them) and respect that this of course is your project to manage as you will. I feel in this case that your stance on not adopting a potential standard is doing more harm than good, given how many people seem to be using it already; rather, adopting this (even with some documented caveats) may actually help push for a standard given how widely nvm is used. I hope this does not come across too blunt; I mean it all with great respect.

If your mind has not been swayed, should this issue be closed? I'm curious why its still open, it gave me hope 😇

ljharb commented 1 year ago

It remains open because i haven’t decided that this will never happen, nor that this should happen. The amount of time that’s passed is irrelevant; whether it’s months or decades, an issue asking for a feature should stay open until it’s a definitive wontfix, or until it’s added.

I appreciate the research done here, and since nvm’s enforcement of constraints on the file would likely constitute a defacto standard everyone else would follow due to nvm’s usage, that might be sufficient to make this a possibility at a future date.

robcresswell commented 1 year ago

Thanks @ljharb, I appreciate the response! Do you have any thoughts on when that future date might be? Is there anything I could follow up on, perhaps with some of the other node version management tools, to help here?

ljharb commented 1 year ago

Nope, I don't typically commit to timelines on releases, let alone on making decisions :-)

The best way to help is to help take things off my plate - for nvm, the main blocker right now is converting travis tests to use Github Actions.

sospedra commented 1 year ago

TLDR - It's 2023 and everyone supports .node-version but nvm. You can use the standardized file with asdf, avn, chnode, direnv, fnm, n, nenv, nodenv, nodist, nve, nvs, setup-node, etc. Not only that, it's the defacto in all the major platforms: Cloudfare, Netlify, Vercel, Paketo, Render, Starship, etc.

But it's not for nvm 🙆‍♂️

ljharb commented 1 year ago

@sospedra that kind of snark is unwelcome and won't be tolerated here.

Ajedi32 commented 1 year ago

Snark or no it's a fair point. It seems pretty clear .node-version is now a de-facto standard, if not a formal one, and NVM is the only notable holdout I can think of. @shadowspawn's node-version-usage repo linked above in several places lays out the case very comprehensively. There are plenty of actual W3C standards out there with far worse adoption than that.

All this has already been said before though; there's little point in repeating it ad infinitum. Upvote and move on.