-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Yarn is not deduping certain packages with * dependencies #6695
Comments
This is causing an issue for some people using our Yeoman generator. As a workaround, we are using resolutions, but since this behavior seems different from other major package managers (and seems to be fundamentally at odds with the @types system, as well as the concept of deduplication), it seemed like a Yarn bug. |
Cf this thread: #3951 (comment)
|
tldr: open a PR on DefinitelyTyped to change the dependencies into peer dependencies 🙂 |
Also, everybody should have a unicorn! If you can't obtain a unicorn for some reason (e.g. you need one of the 5000+ NPM packages that are not part of this awesome fantasy), then you should use a different package manager than Yarn. Ermmm... wait a sec-- we want people to use Yarn, right?! 🙂 |
Filed a similar issue here: #6415 |
I want to think that opening a PR to remove an undefined behavior from a package should be less work than finding a unicorn. But someone has to do it at some point, I guess 🙂 |
But (as far as I know) the current definitions work correctly today with NPM and PNPM, which have two radically different installation strategies. So, in what sense is the behavior "undefined"? Yarn's interpretation seems to be that if I ask for "~1.2.3", I should always get the absolute latest 1.2.99, even if all the other libraries in my locus asked for "1.2.4". That is wasteful, because we have to install, load, and eval two entire copies of the library. It seems pretty reasonable for the package manager to say "1.2.4 is compatible with what you asked for, so it's more economical to give you that." |
To summarize your request:
Is that the work needed to make the @types packages compatible with Yarn? |
Two reasons:
When I say undefined behavior, I mean it in the C/C++ sense: it's undefined in the sense that nothing defines what happens when two packages from the dependency tree overlap[1]. They might be resolved to the same version, but maybe not. And the behavior can change if we need to. [1] Except in Plug'n'Play, where it is standardized that regardless of the position of the dependent package in the dependency tree, the exact same range absolutely must resolve to the exact same version (we can afford to do it there because we're not restricted by the hoisting anymore). Still not guarantees on overlapping-but-different ranges, though (because of the two points I detailed above).
You can work incrementally and fix such packages as they cause issues, but generally yes. You also can send a PR to Yarn to fix the bug that duplicates the resolution, and keep the DefinitelyTyped packages as they are (broken). They'll cause other issues down the road because the core problem won't have been addressed, of course. If you want a hotfix, the |
Thinking about this more, perhaps peer dependencies are appropriate. As I understand it, the rules for
This really does sound like what peer dependencies are supposed to model.
I believe DefinitelyTyped builds and publishes all 5000+ |
@arcanis Correct me if I'm wrong, but doesn't |
Because a "perfect" tree (given any subjective metric) doesn't necessarily use all the latest versions. For example a "perfect" tree (I hate this term so much) where the project depends on [email protected] and B@* would maybe choose the older release if given the choice between [email protected] (which itself depends on [email protected]) and [email protected] (which itself depends on [email protected]), because it would only require to install two packages vs three with the more recent package. |
The most confusing part of this problem is that it behaves non-deterministically. I had been using Yarn for a TypeScript project for months, and I had been lucky to not hit this problem, until one random afternoon it blows up in your face and starts installing mutually incompatible versions all over the place. If Yarn is not able to handle The way things stand at the moment, Yarn cannot safely be used in combination with TypeScript (since almost any TS project is bound to use |
I think you're missing the point, which is that this syntax is supported the exact same way as npm in that we make the same guarantees. Or rather that neither of us make the guarantees that @types is relying on. If the case you describe works with npm it's purely thanks to an implementation detail, and while it would make sense to do something similar for the sake of optimizing the tree a bit more relying on a package manager doing so is invalid and broken. Which kinda downgrade the priority of fixing it on my side (anyone is welcome to open a PR, though). As much as I like TS and the DefinitelyTyped project, it's quite clear that they didn't properly consider the semantic implications behind using regular dependencies. Trust me it's as annoying for me to explain the same problem multiple times (without anyone starting a discussion to fix that on the TS side) as it is for you to experience it ... |
It may be that npm has not explicitly committed themselves to supporting this usage, but as long as it keeps working, I think the odds are fairly slim that a community effort like DefinitelyTyped will bother to rewrite the dependencies of thousands of packages, just to make things work with Yarn. I understand it's annoying, but considering the positively herculean effort in trying to get the DT community to change, to support a minority package manager like Yarn, I don't think it's particularly surprising that nobody has volunteered yet. Don't get me wrong, I really like Yarn and I admire all the people who've invested their time in pushing the npm ecosystem forwards by creating and maintaining an alternative to npm. But not so much that I want to spend weeks, if not months, trying to get all of DefinitelyTyped to change. In fact, given the growing popularity of TS, I think if npm will find themselves having to support this usage. A new version of npm that doesn't work with TypeScript would go over like a lead balloon. |
I talked to the compiler owners about this a couple years ago, and they eventually convinced me that the The basic issues are:
Part of the problem is that the typings are maintained by volunteers who are typically not part of the release process for the underlying library, and often are unable to deliver a quality bar beyond whatever they need to get their immediate problem unblocked. This is why Despite all these limitations, DefinitelyTyped works amazingly well in practice, at least from the perspective of end users who consume And I agree that NPM/PNPM do work very reliably with star dependencies. Theory aside, Yarn clearly has frequent problems that the other package managers do not seem to encounter in practice. |
I don't have anything against If
Yep I totally understand - I spend myself a lot of time advocating for good practices and submitting PRs to fix invalid dependency listings as I stumble upon them. While it's not always the most interesting PRs, I feel like it's important to progressively put back some strictness in the ecosystem. Javascript popularity grew fast, and I think we're reaching a pivotal moment where we need to strengthen our foundations (and tools) rather than doubling down whatever the cost. Anyway, regardless of my personal opinion, I would be willing to review a PR that would help improve this use case and add a regression test to protect against. Any brave soul out there? 🙂 |
In the past (e.g. at least as recently as 4.x), NPM's behavior when installing peer dependencies was so misguided that peer dependencies were effectively useless. (Basically, if you had a dependency chain App->MiddleWare->Library, the MiddleWare package was unable to specify versions for peer dependencies declared by the Library.) During this era, people got frustrated with peer dependencies, and they were widely deprecated. PNPM and Yarn don't have this flaw, and it may be the case that NPM eventually fixed it as well. Recently people seem to be using peer dependencies more, and I haven't heard as many complaints about them. @arcanis if all of the @zkochan would PNPM handle this okay?
I wouldn't personally consider this to require a "herculean effort." If someone could persuasively demonstrate that a different design would significantly improve the DT experience, the code it is pretty much all in one big master branch. It's probably not a big deal to make a sweeping change. |
I think so - the main thing being that it would be the responsibility of the application authors to add those packages to their dependencies (whereas now if you add Btw, I think I'd be open to make @types packages use exact versions by default when running |
I believe the solution described by @arcanis will work with pnpm as well. Pnpm supports peer dependencies and resolves them correctly.
off topic, I'd do that for everything :-) |
Proposal: Maybe Yarn/PNPM could help out by adding a new command line option
...it would get installed as if it had been written like this: {
"name": "@types/lib1",
"version": "1.2.3",
"peerDependencies": {
"@types/lib2": "*"
}
} And when the package manager encounters this: {
"name": "lib3",
"version": "1.2.3",
"dependencies": {
"@types/lib1": "1.2.3"
}
} ...it would get installed as if it had been written like this: {
"name": "lib3",
"version": "1.2.3",
"dependencies": {
"@types/lib1": "1.2.3"
},
"peerDependencies": {
"@types/lib2": "*"
}
} This would allow people to opt-in to this new model and test the waters. If many professional code bases find that this approach works reasonably well, then we could use that evidence to persuade DefinitelyTyped to convert all their packages to adopt it. |
Unless I missed something in this comment chain, everyone keeps talking about the consumer installing all the For example, just look at I don't see how |
I just did a quick audit of the 2,131 NPM packages consumed by a real production repo. This includes internal packages and external packages from npmjs.com, and a mixture of browser libraries and NodeJS libraries. Ignoring
My guess is that only a few of these packages are actively churning. Most have either (1) not had a SemVer-compatible release in a long time, or else (2) are very well-behaved APIs such as lodash. Other may have different experiences. What I observed was that during the evolution of this repo, we spent a long time dealing with frustrating breaks caused by patch-increments for DefinitelyTyped packages, until we eventually managed to lock down a consistent set of version numbers for our application and all its dependencies. That's why the set of To summarize:
|
Ideally, if all of these libraries used Could this also be solved by a Yarn v2 plugin? |
Note that the problem isn't about resolving to From an implementation perspective, imagine that there is a
Technically you could have a resolver that would bind itself on 1 This isn't entirely true in that we do try to apply some optimizations when possible - but generally speaking you should assume that we can't 2 If you were to suggest that we simply reuse the result from |
Hi, I am looking for a practical way to cope with this issue in monorepo. Could You help?
It helped me when the @types/react dependency is hoisted, but when Yarn decides to keep it nested inside specific dependency package's
How to resolve this issue in monorepo? I will add that Yarn's "resloutions" don't work in monorepos :( (Using Yarn 1.15.2) |
@gitowiec I think the only solution atm. is to switch to npm with Lerna. Maybe Tink in the future. |
@mikl Thanks for the reply. But your answer makes me sad. We have a small devs team and this issue is pushing us back. Until now I "fixed" this problem by manually editing yarn.lock. It helped when packages where hoisted from |
We've been using PNPM 3.x which introduced a |
From my reading of what dependencies, devDependencies and peerDependencies are supposed to be (Ignoring bugs in yarn, npm etc.)
|
Well, it is never valid for ambient declarations. For normal declarations it is valid in cases where different versions of the underlying library were installed (and are not being used interchangeably). |
Declarations published under |
This just isn't true. If a library uses a type from a
What about |
I started getting around this by running this alias every time I messed with deps.
|
Do you want to request a feature or report a bug?
Bug
What is the current behavior?
Yarn doesn't dedupe @types packages or packages with
*
range dependencies.If the current behavior is a bug, please provide the steps to reproduce.
https://github.com/nickpape-msft/yarn-react-types
Go in there and run
yarn install
. You would expect there to be only the following versions:You would expect this because the
@types/react
that is installed at the root should satisfy the dependency listed in@types/react-dom
:However, you instead get a side-by-side
@types/react
dependency:This would cause you to get TypeScript build errors (the newest types are perhaps using new compiler features, or you end up with duplicate definitions for stuff that is exported from
@types/react
).What is the expected behavior?
Only the following two packages are installed:
Please mention your node.js, yarn and operating system version.
Node: 8.9.4
Yarn: 1.12.3
Windows 10
The text was updated successfully, but these errors were encountered: