Replies: 3 comments 14 replies
-
I’m unclear on what you’re proposing, but the ability to mutate the latest tag is critical, and must not be impeded in any way. |
Beta Was this translation helpful? Give feedback.
-
Hey @arcanis I've shared this with this team and will follow up when I've had time to think on this a bit more. It seems like the biggest confusion is specifically when you have a semver in the range in the package.json that includes latest, but would install a newer version. In the case that folks publish a An initial thought would be semantically... do we want to be respecting the range in the package.json, or do we think "latest" should trump the "highest possible version" in the range if latest is in the range but not the highest possible version. |
Beta Was this translation helpful? Give feedback.
-
So, to make sure I understand the request here, the idea is:
There are a number of challenges with this approach. First, it will break existing use cases (including one that npm itself uses) for providing releases on a semver-major line ahead of making that semver-major line the "default" installed copy. Second, it could make it much more challenging to release legacy versions of a package. I think this might have been addressed by making the If we do implement this in such a way as to avoid the legacy management problem, then I don't see how the semantics are any less misleading. If the core objection is that "latest" might not actually be the "latest" published, well... if my currently active release line is 3.x, and I then publish 2.2.1 to fix a bug in the legacy 2.2.0 version, then 3.2.0 is no longer the "latest" published. Either we accept this semantic wart, or I'm forced to then publish a no-change 3.2.1 just to re-claim the tag. The much easier solution to this problem would be for Yarn to adopt the same semantics for manifest resolution that npm uses, which is encapsulated in If you would still prefer not to rely on Since a solution to the problems presented is readily available for all to use, and adding this restriction to the registry would break several popular and valuable use cases, I think it is extremely unlikely we will move forward with the suggestion as presented, unless there is a significantly more compelling need to justify the disruption. That said, there is clearly work to be done evangelizing the use of |
Beta Was this translation helpful? Give feedback.
-
tl;dr The
latest
tag can currently point to non-latest releases, making it a semantical non-sense causing problems with tools attempting to give it one. Users should be prevented from modifying it, with it being fixed to whatever the latest stable release actually is at any given point in time. It wouldn't break use cases, because there are better tools to achieve what people typically want by doing this.An annoying problem we've been hitting on Yarn regarding the npm registry has been regarding the
latest
tag on the registry. It's rather subtle, so first I'll explain a bit how things work, why it's problematic, some fixes, and what's the best one and why.Tags on the npm registry work very much like Git: a set of words, where one word points to a version. Just like Git tags, npm's dist-tags are mutable: it's fairly easy to change the target of a tag by using the
npm tag
command. This capability is often used: various popular packages have anext
tag pointing to the highest beta (and thus need to update the tag reference when a new beta is published), and even without that an overwhelming majority of packages make use of thelatest
tag, which always point to the latest stable release from a package.Before going further, let me talk a bit about
yarn add
(npm add
doesn't work exactly the same but suffers from the same problem, in different ways). When you run the command with a range (yarn add foo@bar
), things are fairly simple: you tell us you want to usefoo
at versionbar
, so that's what we put in thedependencies
field. Easy. Now, what happens when you runyarn add foo
, though? Since there is no explicit version requested, we fallback onlatest
, which we resolve to whateverlatest
is currently assigned on the registry, and then finally we store that in the manifest as a range (let's say^1.0.0
). Fair enough, right?And now is the fun part: what happens if
latest
doesn't point to the latest stable release? That sounds a bit weird, but it's actually very possible. The npm registry doesn't currently enforce whatlatest
points to, so you can usenpm tag
to update it to an earlier release (I hear someone in the back say that's kinda like unpublishing a package, but safest, right? - let me continue and we'll come back to that later). As an example, Husky currently has the following releases (minus a few that aren't relevant to the problem at hand):We can notice a few things:
latest
tag doesn't point to the highest stable (that would be5.0.4
)4.3.1
), which is probably a mistakenext
tag doesn't point to a semver prerelease, which is probably a mistake tooThat's kind of a mess ... but so what, will you ask me? Let's go back to
yarn add
. If you install Husky at the moment with Yarn (2), you'll have an funny behavior: Yarn will resolvelatest
to whatever the registry says (4.3.0
), turn it into a range (^4.3.0
), and add that to thedependencies
field. Then it'll run an install, and that's when things become interesting! Because when Yarn sees a range in its dependencies (like^4.3.0
), it'll resolve that by asking the registry the list of all versions, keep only the compatible ones, and use whatever the highest is. Which, in this case, would be4.3.1
. As a result, you get a slightly awkward behavior where the range in the manifest doesn't represent the version who got installed (but is still perfectly compatible with it).One question I can hear: is it a bug in Yarn? As I mentioned earlier, tags are words pointing to releases. In themselves, they have no bearing on the semver resolution - just because a release has a tag doesn't change anything regarding whether it is compatible or not with a range. Since
4.3.1
is compatible with^4.3.0
, then there's nothing preventing it from being selected... which can be surprising - we got at least two/three issues about this in the past year.So what can be done to prevent that?
Yarn could ignore all versions higher than
latest
for the purpose of semver range validation. I don't like that, because it's the kind of magical workaround that's susceptible to break in unexpected way (what if I use a range to a prerelease? What if I use*
? etc)Yarn could make
yarn add
smarter by storing an exact range (4.3.0
) instead of a caret range when it detects that alatest
semver range would match more than one unique version. This is undesirable because:It would break commands like
yarn upgrade-interactive
, which would lose valuable information (that the user intends allows this dependency to be upgraded to future versions within the same major).It would break systems that enforce caret dependencies (or, more generally, would be confusing to many users that wouldn't understand why some dependencies are ranges and others exact).
Yarn could use a literal
latest
tag in the dependencies field (instead of a semver range) when it detects that alatest
caret range would match more than one unique version. It would address the first problem, but leave the second: it would be very confusing to have one behavior or another without clear idea why.We could do what npm does, and use
^4.3.0
and have some internal logic to install4.3.0
during the followup install, rather than the highest compatible version. The would solve the confusion, but would leave theupgrade-interactive
problem.We could completely ignore whatever the
latest
tag points to, and letyarn add
find out what's the highest stable version available. In Husky's case however that would be5.0.4
, not4.3.1
.I find this latest option the most interesting one, because the only real blocker is that Husky made a mistake by publishing a prerelease (
5.0.4
) as semver-stable, and thus it would be accidentally installed. But still, that's problematic! How to fix this if it happens? This bring me back to the question I put aside earlier:This scenario is the only case where it makes sense to pin
latest
to not-latest. This way, people runningyarn add
won't accidentally use your accidental release. However it's also flawed: they still can upgrade to it, since the range will still match. What we need is a way to say "hey, I don't want this version to ever be considered for resolution, unless explicitly requested", so that package authors could truly "unpublish" a package, but without removing it from the registry (which could break projects who already started relying on it).Fortunately this already exists! Package versions can be deprecated, and package managers can use this heuristic to make them secondary during resolution, to prefer the non-deprecated versions when possible. Through this mean, we have a proper way to satisfy the only use case for pinning
latest
to an earlier version - thus removing the only blocker that would prevent makinglatest
immutable.Beta Was this translation helpful? Give feedback.
All reactions