nvm-sh / nvm

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

Semver range support #2562

Open alexkrolick opened 3 years ago

alexkrolick commented 3 years ago

I know the preferred way to reference ranges in nvm is with lts/name, but we've run into an issue when pkg.engines has to specify a minimum value for the minor version, ie >= 10.13.1. Without switching to an exact version, users who don't habitually update their nvm references will not get the memo to update to the minimum.

Allowing ^10.13.1 or something like that would allow a minimum version without capping the maximum version, which is desirable.

ljharb commented 3 years ago

pkg.engines is a range, altho it's often used in apps to target a single version.

nvm does not in fact support ranges - lts/ aliases target a single version out of a subset. lts/argon, for example, means v4.9.1, and only that version, full stop.

Is your use case for an app, or a package?

alexkrolick commented 3 years ago

The use case is for an app.

lts/argon, for example, means v4.9.1, and only that version, full stop.

Right, the problem is since it's a rolling pointer, if a dev doesn't update the reference using nvm install periodically, they can fall behind without knowing it. So if you rely on behavior from a minimal version in a release series specified in pkg.engines, and assume that lts/whatever will be the maximum of that release series, you can run into an issue when a local pointer is lagging. Hence the desire to increase specificity of the minimum version while still allowing a higher maximum version.

ljharb commented 3 years ago

I see - so if I understand correctly, you want a way in .nvmrc to say lts/argon but ALSO to say 4.9.1, so that if someone has a local lts/argon that's behind, they'll get a warning?

Note that any remote connection will update the local user - you could, for example, add to your app's preinstall script something like nvm version-remote node >/dev/null and it will silently update their local aliases, so that nvm use will report that the right node is not installed. Would that suffice?

alexkrolick commented 3 years ago

I see - so if I understand correctly, you want a way in .nvmrc to say lts/argon but ALSO to say 4.9.1, so that if someone has a local lts/argon that's behind, they'll get a warning?

Yes, but it seems fairly hard to express that with release codenames, so semver notation like ^4.9.1 or the equivalent >=4.9.1 < 5 would also work.

Note that any remote connection will update the local user

I suppose this works. It's not precise but I guess in combination with the engines field, the end result will be that devs roll forward whenever possible and can't install on less than the minimum version.

ljharb commented 3 years ago

Unfortunately to parse semver notation would require a very large and complex chunk of code in shell scripting, so that's not really feasible.

alexkrolick commented 3 years ago

I'll settle for documenting the workflow above, but I'll also propose this if it seems valuable to automate:

4.9.1 # installs just this
lts/argon # installs local pointer
min: 4.9.1 # same as just 4.9.1
max: 4.9.1 # same as just 4.9.1
max: lts/argon # same as lts/argon
min: 4.9.1
max: lts/argon # installs lts/argon unless it is behind min
min: 5
max: 4 # error

(I think the formal way is also better than automating the fetch using package scripts because some people may need to use the--reinstall-packages-from flag to properly update)

ljharb commented 3 years ago

We'd need to define semantics for min: 4.9, max: 4.9, etc; also, nvm doesn't track which versions used to be LTS - not sure if that'd be required.

alexkrolick commented 3 years ago

nvm doesn't track which versions used to be LTS - not sure if that'd be required.

I don't think it would be, you'd just turn the local lts pointer into a fully qualified version and see if it matches the constraint

justsml commented 2 years ago

What if the .nvmrc file specified a list of supported versions, and it used the first version to match locally installed versions:

14.12.*
14.19.*
16.*.*
12.17.*

If this is breaking change, then perhaps a .node-versions (plural) file would be appropriate?

ljharb commented 2 years ago

@justsml nvm doesn't understand stars like that, but 14.12, 14.19, etc would work. However, it would definitely be a breaking change.

Something with a non-nvm-specific name wouldn't be able to support nvm-specific ranges, like aliases, or 14.12 - it'd have to take full versions only.

FranCarstens commented 2 years ago

Using the following in .nvmrc works for us, but...

node-version = >=14.19.1||<15.0.0
engine-strict = true

We get a semver warning npm WARN invalid config node-version=">=14.19.1||<15.0.0". Any way to turn that off?

ljharb commented 2 years ago

@FranCarstens that's npmrc, not nvmrc, and that definitely will not work for nvm.

ljharb commented 1 year ago

(re engines.node, linking to #651)

leannechen commented 9 months ago

Just to mention that we encountered same problem in our app.

Some of our app's dependency packages require Node >= 16.14, and we are strugging how to set a corrresponding version in app's .nvmrc.

Option 1: v16 in .nvmrc If 16.12 is the shell's original nvm default, it won't be aware that it should install and switch to 16.14 even with integration, because 16.12 is satisfying v16 in .nvmrc.

Option 2: v16.14 in .nvmrc It comes up with two problems. First, if someone has 16.18 as default on her local machine, she has no choice but to install 16.14 -- even 16.18 has satisfied the >= 16.14 requirement in package.json. The second is that both package.json engines.node field and .nvmrc are specifying Node version

ljharb commented 9 months ago

@leannechen add a CI check that both are in sync, and you shouldn’t want some devs on 16.18 if your app is tested and deployed on 16.14 - iow, for an app, you should use a full 1.2.3 version.