-
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
Improper hoisting of peerDependencies: webpack, ajv, ajv-keywords #3933
Comments
For posterity, this can be circumvented by adding |
This seems like the intended behavior to me. |
@kaylieEB Your argument definitely has some merit for shallow dependency trees like the original example, but there're some problematic implications of thinking about First,
Further, it is impossible to install multiple versions of the same peerDependency at the top-level, so it's easy to see if we take this example a step further...
As we can see in the above example, if the top-level
If the top-level project no longer has a need for
In short, This would effectively make Again, the effect of This would be a de facto breaking and (likely) fatal change from |
Thanks for the explanation, I can now see the issue in your complex scenario. It seems like peer dependencies need to be aware of its requested context and be placed relative its parent dependency, instead of being deduped and being hoisted like other dependencies. In some scenarios, this may mean that a top level dependency somehow needs to be nested elsewhere since there's only 1 global peer, even though there may just be one of that top level dependency, because the position of its peer dependency is already taken up by another. This seems like a pretty significant change to the current hoisting logic. Thoughts on this @BYK @arcanis? |
I'm not entirely convinced that what Yarn does is incorrect here. The scenario explained to me looks more like a dependency clash where different dependencies require different versions of their peer dependencies, causing a clash during hoisting. @CrabDude instead of explaining this in as prose, would you be okay creating a minimum test case that we can see with some
This would also help us write a test case if/when we fix this. Finally, I have a feeling that #3868 may help alleviate this issue. What do you think? |
@BYK Agreed. This is the problem. My examples demonstrate and explain why it's a problem for In short, there are 2 ways to looks at this:
Here are several examples, including the real example in the OI, of EXAMPLE: OriginalThis {
"dependencies": {
"babel-cli": "^6.24.1",
"stylelint": "^7.9.0",
"webpack": "^3.1"
}
} EXAMPLE: 1{
"dependencies": {
"dep-a": "*"
}
} {
"name": "dep-a",
"dependencies": {
"babel-cli": "^6.24.1",
"stylelint": "^7.9.0",
"webpack": "^3.1"
}
} EXAMPLE: 2{
"dependencies": {
"dep-a": "*"
}
} {
"name": "dep-a",
"dependencies": {
"babel-cli": "^6.24.1",
"ajv": "4", // Insufficiently addresses incorrect hoisting
"stylelint": "^7.9.0",
"webpack": "^3.1"
}
} EXAMPLE: 3{
"dependencies": {
"dep-a": "*",
"ajv": "4" // Extraneous at the consumer level, but required due to incorrect hoisting
}
} {
"name": "dep-a",
"dependencies": {
"babel-cli": "^6.24.1",
"ajv": "4",
"stylelint": "^7.9.0",
"webpack": "^3.1"
}
} EXAMPLE: 4{
"dependencies": {
"babel-cli": "^6.24.1",
"stylelint": "^7.9.0",
"webpack": "^3.1",
"ajv": "4" // Extraneous at the consumer level, but required due to incorrect hoisting
}
} In this final example, if Effectively, the same |
@CrabDude - I think I understand some of the problems but, your examples are still not clear enough to clearly and reliably reproduce this case. Please provide us the following: A repo/gist that demonstrates your case, complete with stable Right now it is tough to separate what is happening, what should be happening and, what are your personal views about how it should be done. Makes sense? |
Your statements frustrate me. With each of the examples, you personally can reproduce the described outcomes with 100% consistency, the definition of reliable facts. You're also not responding directly to any of the examples specifically, or their objective 100% reliable/reproducible outcomes.
1. What is happening?The same
This is what my examples demonstrate, that 2. What should be happening?A constant This is objectively different from 3. What are your personal views?This implementation is incompatible with the ecosystem and contrary to the design and canonical implementation of 4. How should it be done?As |
I'll add that I will put together the repo as requested, despite my concerns about the present effectiveness of my communication. |
Pretty sure @BYK doesn't want to frustrate you, @CrabDude - to give you some context, we're currently very hard at work on closing the critical issues remaining to publish a 1.0 RC, so right now we really need to be spoon-fed on issues requiring brain time 😄
Thanks a lot! We'll look at this and come back to you. I understand this might be frustrating, but please rest assured we'll give this issue all the attention required - we're just having a lot of context switches at the moment! |
I've closed #3916 which was a duplicate of this. I agree that this is a Yarn issue, not a package issue. For the package in question, Yarn could install dependencies in a way that doesn't break the peer dependency constraint, but it doesn't, because it ignores that constraint when hoisting. |
Ok, I think I got it, that's definitely a bug. Yarn should not hoist a dependency past the point where it would be able to require its own dependencies, whether they're defined as regular Here's a repro script based on the first comment - when running this script, the final line should be rm -rf foo
(
mkdir -p foo && cd foo
echo '{"dependencies":{"a":"file:./a", "d":"file:./d", "e":"file:./e"}}' > package.json
echo 'require("a")' > index.js
)
(
mkdir -p foo/a && cd foo/a
echo '{"name":"a", "version":"1.0.0", "dependencies":{"b":"file:../b-2", "c":"file:../c"}}' > package.json
echo 'require("c")' > index.js
)
(
mkdir -p foo/b-1 && cd foo/b-1
echo '{"name":"b", "version":"1.0.0"}' > package.json
)
(
mkdir -p foo/b-2 && cd foo/b-2
echo '{"name":"b", "version":"2.0.0"}' > package.json
)
(
mkdir -p foo/c && cd foo/c
echo '{"name":"c", "version":"1.0.0", "peerDependencies":{"b":"2.0.0"}}' > package.json
echo 'console.log(require("b/package.json").version)' > index.js
)
(
mkdir -p foo/d && cd foo/d
echo '{"name":"d", "version":"1.0.0", "dependencies":{"b":"file:../b-1"}}' > package.json
)
(
mkdir -p foo/e && cd foo/e
echo '{"name":"e", "version":"1.0.0", "dependencies":{"b":"file:../b-1"}}' > package.json
)
(
cd foo
yarn
echo
tree node_modules
echo
for x in $(find node_modules -name package.json); do
echo $x
jq .version < $x
done
echo
node index.js
) |
@arcanis Thanks for putting this together. Is there a list of outstanding issues for the 1.0 RC? I don't see a Milestone or label for it. |
We try to group everything inside this project |
@CrabDude - I certainly didn't want to frustrate you, and I appreciate all the time you've put into this issue and your explanations. The problem I have is a large volume of issues that we have to verify: is this an actual bug, is this a feature request disguised as a bug, is this a need for parity with npm where we don't have to etc. Having the whole issue described as prose and not as simple as "get the For this specific example, it required a lot of time to understand, and then manually reproduce the issue. On top of that, the dependencies you use to demonstrate have lots of sub dependencies making the issue harder to isolate. |
Thanks @BYK & @arcanis. I said "frustrated" to allow for things being as you have described them, in recognition that it may very well be due to my choice of communication. From my perspective, it did not seem the Thanks for your patience and work on the project. |
Because of a [yarn bug](yarnpkg/yarn#3933), `ajv` peer dependencies cause `yarn check` to fail if we just let yarn do its thing. As a workaround, add `ajv` to dependencies explicitly.
Currently working on a fix - I managed to fix the testcase exposed above, but I still have an error when running |
Following the issue for updates. Thanks! |
**Summary** Fixes #3933. Currently, the code hoists depedencies without ensuring hoisting doesn't break the final structure's `peerDependencies` requirements. This patch fixes that by adding extra checks before hoisting. It comes with a little performance impact but shouldn't be too much. **Test plan** A new integration test that simulates the reported behavior and ensures `yarn` now behaves correctly.
Because of a [yarn bug](yarnpkg/yarn#3933), `ajv` peer dependencies cause `yarn check` to fail if we just let yarn do its thing. As a workaround, add `ajv` to dependencies explicitly.
Because of a [yarn bug](yarnpkg/yarn#3933), `ajv` peer dependencies cause `yarn check` to fail if we just let yarn do its thing. As a workaround, add `ajv` to dependencies explicitly.
ajv is a peer dependency that we had to declare explicitly because of a Webpack bug. That bug [has now been fixed](yarnpkg/yarn#3933 (comment)).
Do you want to request a feature or report a bug?
bug
What is the current behavior?
foo
listsdependencies
:bar@5
baz
baz
listspeerDependencies
bar@5
.qux
&quux
listdependencies
bar@4
bar@4
to hoist, invalidatingbaz
's peerDependency ofbar@5
)The result is the following tree:
If the current behavior is a bug, please provide the steps to reproduce.
What is the expected behavior?
Don't hoist dependencies (i.e.,
baz
&ajv-keywords
) w/o hoisting peerDependencies (i.e.,bar
&ajv
).In the example above,
ajv-keywords
should not be hoisted, and left as a sub-dependency ofwebpack
.Please mention your node.js, yarn and operating system version.
yarn@0.28.1
node@4.8.2
Related:
#3465
#2688
Dupes:
#3916
webpack/webpack#5262
The text was updated successfully, but these errors were encountered: