avn
avn copied to clipboard
Read node version from package.json
Perhaps I'm missing something, but why not use the package.json? why are we creating another meta file that duplicates a piece of information about node that can already be stored in the package.json?
- https://docs.npmjs.com/files/package.json#engines
- https://docs.npmjs.com/files/package.json#enginesStrict
That field is a) information-only, and b) identifies what something is supported with. That field can't be easily used to test a new version.
I'm open to the idea of using another field in package.json
to specify the version. As @ljharb mentions, it shouldn't be the engines
. But I would want to replace (deprecate) the use of the .node-version
file to keep the tool simple and also make sure it easily supports all use cases.
Here are some use cases that come to mind:
- A project/folder that doesn't actually use
npm
, simply usesnode
in some way. - Having a project where you want a
.node-version
file that isn't version controlled. While this probably isn't the majority use case, it still seems like a nice to have. - Writing a build/test script that changes the version being used by overwriting the
.node-version
file. This could be achieved instead by having that same script simply change the version used with the actual tool instead of usingavn
. - Writing a build/test script that needs to read the node version being used, but is written in a language (like bash) that doesn't easily read JSON files. This could easily be considered to be that script writer's problem.
Another argument against this would be keeping things similar to the ruby tools, but there's not really a strongly compelling reason to do that.
At this point, I think it makes sense to stick with the .node-version
file, but I still have an open mind about it and would love to start a dialog with anyone who wants to discuss.
@ljharb, with regard to (a), isn't the engines
property an actionable piece of information that allows platforms like Heroku to execute a series of processes that make the project associated with the package.json
file usable?
Wouldn't the engines
property allow a tool like avn
to execute an action (such as nvm use x.y.z
) to make the project associated with the package.json
usable (such as actions, like building node modules, that require a supported version of Node).
As for (b), could you explain the deficiencies in the engines
property that prevent it's use for testing? (For example, my impression is that once I'm in a folder that contains a package.json
file with the Node version set to 0.10.x
, that I'm not prevented from running nvm use 0.12
to test that it's compatible. I simply assume some risk that I may not have a good experience.)
If #17 is completed, this may be less likely to change. It would complicate the code base to support .nvmrc
as well as package.json
.
This would be handy. It's a little annoying having to keep the node version for our project up to date in 2 places. One simple pass would be to ignore it if an exact version is not specified.
@mockdeep the only concern now is that avn
searches for files containing version information. That function would need to be updated to scan for package.json
and only consider it to be a file for versioning info if it contains engines
. The function must be fast as it's invoked for every directory change.
Also, we would need to handle the file differently when it's read.
I'm open to these changes, and would want to decide if engines
was truly the right property to read from, but that should be an easy adjustment once the code is written. PR welcome! :smile:
I just wanted to chime in on this;
We already use "engines": { "node": "x.x.x" }
to make heroku install the correct node version for all our apps. If platforms are already doing this - why can't your local machine do that (with this tool)? It just seems redundant and error prone to have to maintain two separate fields/files that will always be identical.
Other than that - love this - great work! :)
@eiriklv engines
takes a semver range, so it can match any number of node versions, not necessarily just one.
@ljharb isn't that a good thing? :-)
My point is - when this works really well on Heroku - why shouldn't it work great anywhere else..?
Is the issue here shortcomings of the tool (that it only supports a specific version)?
@eiriklv no shortcomings with avn
, but the way that it works is to look at the installed versions that are available on the machine rather than attempting to install the latest.
So if you specify >= 0.12 <5.0
in engines
and one developer has 0.12
installed while another has 4.2.2
, they'll be using different versions when developing.
I don't consider this a problem — that's just how it works at the moment. Currently avn
should allow you to specify a semver range in the .node-version
file (though it's not documented & I don't believe it's tested either). So arguably, avn
already exposes the possibility of developers using different versions.
I don't see the problem with a semver range in engines
— it's a choice that teams can make. We can default to reading .node-version
for projects that need a semver range, but want devs to use the same version when working on the project. Also, I feel the issue of which version gets used can be addressed via documentation.
My main point here is - why add another (duplicate) reference to the node version when you already specify it in "engines"
. I don't want to have to keep things in sync :-)
The optimal solution would be that avn would tell n or nvm to install/use the latest available version in the specified semver range
Edit: And thus behaving the same way on your local machine as on Heroku (as an example) Edit2: Or am I missing the intention of this tool?
@eiriklv that's more or less the intention, but without support from n
and nvm
, this tool won't be able to handle something like >= 0.12 <5.0
. It can't just say n '<5.0'
, for instance.
It selects the lasted available version that's installed locally, not that's available out on the internet.
It could fetch a list of known node versions, but it would then require a network connection which has two issues:
- That's really slow when you
cd
into a directory - This tool should work when you're not connected to a network (attempting to get a list of node versions, but fall back to using the best one installed feels like a bad/inconsistent user experience)
Note that nvm
, while it does not support semver ranges, does support partial identifiers - ie, x
or x.y
or x.y.z
. Also, most of the commands only look locally - just ls-remote
and install
talk to the network.
I'd be okay with choosing the most recent matching version that is installed. If people put a range, then they are responsible for dealing with the inconsistencies across versions themselves. Instead of installing it can just say "no compatible version of node installed" or the like. rvm
does something along those lines:
ruby-1.8.7-head is not installed.
To install do: 'rvm install ruby-1.8.7-head'
What is the status of this?
I was going to open an issue related with setup a default version if node-version
file is not present, but this solution is better to force you have a good package.json
.
@Kikobeats this is still in the discussion phase — implementing this will require a decent number of changes. It also requires that we make decisions that are logical and appropriate for the community. Feel free to weigh in on the points discussed so far and continue the discussion.
I think that is the right way. Now node devs need to handle with different node versions and is horrible the current workflow.
Could be implemented with backward compatibility: if .node-version
file is detected, then use the version declared; in other case try to read the version of the package.json
. I feel that only is necessary add read package step in the algorithm.
less is more!
So what is the status of this issue now?
It's been a year since it was opened.
@sodatea still discussing, but I'm leaning toward it being a good idea.
I'm happy to accept a PR, but we still do need to figure out what key it should look for in package.json
.
I'm using nodengine for this purpose, more simple :smile:
Is package.json
still not supported?
I'm happy to accept a PR, but we still do need to figure out what key it should look for in
package.json
.
@wbyoung, what would be wrong with "engines"->"node"
. What are the other options?
That’s a range, not a single version.
@ljharb doesn't .node-version
work the same way?
I believe that’s typically a single version. nvmrc is a “version-ish” which can be a range, but is expected to resolve to a single version. npm install has the expectstion that it will select the latest available matching version; i don’t think
nvm use` or similar necessarily would have the same intuition.
I don't get it. What do you mean by "typically a single version"? To me it has exactly the same meaning as "engines" fields in packages.json — it specifies node versions that are compatible with my project.
What other meaning it can have? What would be the case when you specify one version in .node-version
and other in package.json
?
The engines field is a semver range; it can describe >= 0.10
or < 11
or ^3 || ^4 || ^6
etc - when you type it, you’re explicitly including all versions that fit in that range; you’re not trying to point to a single one.
nvmrc is a specifier that points to a single version implicitly. When you type it, you’re referring to a range of possible versions, but your intention is that it resolves to a single one.
Conceptually, these are for two very different purposes, and the engines field isn’t a concept that directly maps to “a single node version to install”.
Maybe the problem is that we are talking about different stuff? I am not really familiar with nvmrc
because I am using n
, anv-n
and .node-version
.
The engines field is a semver range; it can describe
>= 0.10
or< 11
or^3 || ^4 || ^6
etc - when you type it, you’re explicitly including all versions that fit in that range; you’re not trying to point to a single one.
Sorry, I still don't get it. Wherever you use it, you'll end up with one resolved version of node, no?
https://docs.npmjs.com/files/package.json#engines You can specify the version of node that your stuff works on
So I use it to specify version of node that my stuff works on. Then, for example, when my CI tries to build my stuff, it can look into this field and check wether version of node is ok and if not.
Now, I need to do the same thing, but for all developers who works on my stuff. I use .node-version
. Because I want my CI to build the same stuff as we are working on, I will use the same range as I specified in package.json. Otherwise, it is possible, that succusessful local builds will become failed builds on CI.
What am I missing?
(nvmrc and node-version are the same, conceptually)
Yes, you certainly can take a range and end up with one resolved version - this isn’t a technical barrier, it’s a conceptual one. The mental model of “engines” is simply not appropriate to apply to “which node version should i be using with the project by default” because they are distinct concepts.
It’s certainly valid for you to chose to make them have identical texts (not that node-version of nvmrc should be semver; they’re a subset) - but that doesn’t mean that choice should be foisted on everyone else (iow, the things i put in the engines field for my packages should never be used to select which version to use, so this tool shouldn’t do that)
How are you using it? You are using narrower range or specific version in .node-version
that is included in engines
range?
The mental model of “engines” is simply not appropriate to apply to “which node version should i be using with the project by default” because they are distinct concepts.
I don't see what causes this conclusion. In official docs I see nothing about mental model of this field. It only says:
You can specify the version of node that your stuff works on
To me, it means: "You can choose whatever version from this range, this app will work with it".
I mean, if I am specifying versions of Node which my app supports, it would be strange that I am prohibiting some of them from using in development. No?
@Bessonov that’s both full of a bunch of false claims and also off topic for the thread; let’s not get into that.
@rusty-key nope. Babel 7 requires node 6+, for example, but i have packages using it that support back to node 0.10. I also have a repo where we have binary deps that require node 8 for dev, but the package works fine in production from 0.10 - 11.
Works fine and guaranteed to work fine are not the same. If I specify "engine", I give you some kind of guarantee that my package works with these node versions. It still can work with other versions, but I cannot be sure for some reasons.
Anyway, even if we decide that version file and engines field have different mental models (which I am still not convinced in 😄), I don't see how it prevents avn
from using engines too. It could be a simple precedence rule: if there are no version files around, use any version that satisfies engines
. Would that work?
I don’t think that would be correct, no - i think the engines field is to declare compatibility, and can’t ever be correctly used to determine version switching absent an additional signal.
Hey guys, are there any udpates on this?
@dmitriyaa I'm still at a point of not feeling convinced either way as to whether it's a good idea or a bad one.