npm / cli

the package manager for JavaScript
https://docs.npmjs.com/cli/
Other
8.33k stars 3.06k forks source link

[BUG] Unable to resolve peer dependency if version contains ">=" #2120

Closed RobinWijnant closed 3 years ago

RobinWijnant commented 3 years ago

Current Behavior:

When resolving a peer dependency that has a ">=" in it's version, npm uses the latest version of that package to compare with the current dependency version in the package.json.

In this case: npm is looking for react 17, while react 16.13 is also a version that is suits >=16.9.0

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: test-peers@1.0.0
npm ERR! Found: react@16.14.0
npm ERR! node_modules/react
npm ERR!   react@"^16.13.1" from the root project
npm ERR!   peer react@">=16.9.0" from @testing-library/react-hooks@3.4.1
npm ERR!   node_modules/@testing-library/react-hooks
npm ERR!     @testing-library/react-hooks@"3.4.1" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer react@"17.0.1" from react-test-renderer@17.0.1
npm ERR! node_modules/react-test-renderer
npm ERR!   peer react-test-renderer@">=16.9.0" from @testing-library/react-hooks@3.4.1
npm ERR!   node_modules/@testing-library/react-hooks
npm ERR!     @testing-library/react-hooks@"3.4.1" from the root project
npm ERR! 

Expected Behavior:

npm should be able to resolve the react@16.13.1 peer dependency from @testing-library/react-hooks@3.4.1 because react@16.13.1 is a dependency that matches react@>=16.9.0.

Steps To Reproduce:

  1. mkdir test-peers
  2. npm init
  3. npm install react@16.13.1
  4. npm install @testing-library/react-hooks@3.4.1

Environment:

RobinWijnant commented 3 years ago

I have to downgrade @testing-library/react-hooks@3.4.1 because the peer react-test-renderer@">=16.9.0" will resolve in react-test-renderer@">=17.0.1". This version of react-test-renderer needs in turn react@"17.0.1"

ljharb commented 3 years ago

@RobinWijnant you shouldn't need to do that; but you will need to manually specify react-test-renderer@16 as a dev dep.

isaacs commented 3 years ago

Hmm.... yeah, so the react-test-renderer@">=16.9.0" peer dep resolves to react-test-renderer@17.0.1, which requires react@17, and because @testing-library/react-hooks@3 requires react-test-renderer@>=16.9.0, it resolves to that higher version.

We do aggressively dedupe peerDeps, so if something else were pulling in a lower version of react-test-renderer, we'd use that instead of 17, but what we don't do is roll back to an earlier version if it ends up bringing in a peer later down the line.

Eg:

a -> PEER(b@>=1)
b@1 -> PEER(c@>=1)
b@2 -> PEER(c@>=2)
c@1 -> PEER(d@>=1)
c@2 -> PEER(d@>=2)
thing -> (a, d@1) <-- this will cause troubles, because a->b@2->c@2->d@2 conflicts with d@1

The only way to resolve this would likely be to build up a full pubgrub style ruleset. We sort of approximate such a thing today, but rely on heuristics and nesting to get out of some of the stickiest situations.

This also highlights the problem with using >= rather than ^. We might be able to skirt around the worst hazards by preferring a >= match which is also within the ^ range, where possible. In that case, the >=16.9.0 would resolve to the same as ^16.9.0, but be able to dedupe against 17.0.1 if necessary.

Either of these ideas probably merit an RFC though.

isaacs commented 3 years ago

Actually, just preferring a ^ match when >= is used won't do it. Too many packages out there have peer dependencies like webpack@^4.1.0 || ^5.0.3, and catching every possible iteration won't work out. Eventually, we're always going to have NP-hard territory to venture into.

csvan commented 3 years ago

I don't believe this should be closed. It currently breaks standard NPM7 installs of several major dependencies, such as for example styled-components:

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: @myproject@0.0.0
npm ERR! Found: react@16.14.0
npm ERR! node_modules/react
npm ERR!   dev react@"^16.8.0" from the root project
npm ERR!   peer react@">= 16.8.0" from styled-components@5.2.1
npm ERR!   node_modules/styled-components
npm ERR!     dev styled-components@"^5.0.0" from the root project
npm ERR!     peer styled-components@">= 5" from jest-styled-components@7.0.3
npm ERR!     node_modules/jest-styled-components
npm ERR!       jest-styled-components@"^7.0.0" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer react@"17.0.1" from react-dom@17.0.1
npm ERR! node_modules/react-dom
npm ERR!   peer react-dom@">= 16.8.0" from styled-components@5.2.1
npm ERR!   node_modules/styled-components
npm ERR!     dev styled-components@"^5.0.0" from the root project
npm ERR!     1 more (jest-styled-components)
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR! 
npm ERR! See /Users/csvanefalk/.npm/eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/csvanefalk/.npm/_logs/2020-11-15T08_19_37_425Z-debug.log

I understand that the solution is complex (and I have nothing to contribute myself), but until one is in place it is probably useful to keep this (or a similar) issue open as a reference point for people running into it.

On that note, the above is temporarily resolvable by passing the --legacy-peer-deps flag.

ljharb commented 3 years ago

Seems like you’re missing a top-level dependency on react-dom (that matches the same minor as react itself). If you fix that, what happens?

csvan commented 3 years ago

@ljharb yes, it works if I add explicit dependencies at the top level like in npm6, but my understanding was that npm7 resolves and installs peer dependencies in a way that meant this was no longer necessary, sorry if I got this wrong: https://github.com/npm/rfcs/blob/latest/implemented/0025-install-peer-deps.md

The problem seems to be that since the peer version of react-dom in this case is >= 16.8.0 (this is true for all my dependencies and sub-dependencies, none of them have a peer dependency on React 15 or 17), npm7 resolves the latest available version (17.0.1 in this case), but then concludes that it is not a match for the peer dependency.

ljharb commented 3 years ago

It’s sometimes no longer necessary, but it’s still always better to be explicit.

abaidbutt commented 3 years ago

please use the LTS version of node it help me a lot to save my life in peer dependencies tree errors when install a dependency with npm in react-native it give me this error my issue resolve using LTS version of Node.

csvan commented 3 years ago

please use the LTS version of node it help me a lot to save my life in peer dependencies tree errors when install a dependency with npm in react-native it give me this error my issue resolve using LTS version of Node.

You can get the same behavior in npm7 by passing the --legacy-peer-deps flag for now

jaquinocode commented 3 years ago

For anyone coming from a web search, in this thread ljharb suggested installing an older version of react-test-renderer that's actually compatible w/ the issue creator's project's version of react by installing react-test-renderer@16 as a dev dep. So basically, you should run this command:

npm i react-test-renderer@SOME_VERSION --save-dev where SOME_VERSION is the general version of react that you're using in your project.

For instance, in my project I have react version 16.13.1 installed as listed on my package.json. So for me the command would be:

npm i react-test-renderer@16.13 --save-dev

For me that fixed my issue with installing react-test-renderer & I was able to properly install it.

Edit: you might want to also edit the semantic version for react-test-renderer in your package.json so that's its a fixed version (e.g. "^16.13.1" => "16.13.1"). So that way the exact version you want always gets installed. Or better yet, use a ~ like ~16.13.1, which at least allows for minor patches.

ljharb commented 3 years ago

You don't need it to be a fixed version; the ^ will still work because it won't install v17, and using it is a best practice.

jaquinocode commented 3 years ago

With the ^, version 16.14 for the test renderer would install which requires 16.14 for React. I'm using 16.13.1 for React. So then it would give an error. So I got rid of the ^ to fix it.

ljharb commented 3 years ago

Fair enough - with react, you probably want to use ~ so that the minors are pinned.

jaquinocode commented 3 years ago

Ah, thanks I forgot about that good idea.

On Tue, Mar 16, 2021, 7:27 AM Jordan Harband @.***> wrote:

Fair enough - with react, you probably want to use ~ so that the minors are pinned.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/npm/cli/issues/2120#issuecomment-800305794, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGXXPQ3THXJMGTMS3PQTCVDTD5TGLANCNFSM4TJ5WXZA .

mauricioross commented 1 year ago

Hi everyone, I have the same problem, I must upgrade the proyect to latest version of NxMonorepo, in this project have a app with next js and react, then next js and react also upgrade:

latest version are:

"dependencies": { "@nrwl/next": "15.4.3-beta.2", "@types/ineum": "187.0.1", "core-js": "3.26.1", "crypto-js": "4.1.1", "express": "4.18.2", "hash.js": "1.1.7", "js-cookie": "^3.0.1", "jsencrypt": "3.3.1", "next": "13.0.0", "next-seo": "4.29.0", "next-transpile-modules": "^10.0.0", "react": "18.2.0", "react-dom": "18.2.0", "react-html-parser": "^2.0.2", "react-is": "18.0.0", "react-markdown": "6.0.3", "react-player": "2.11.0", "react-responsive-carousel": "3.2.23", "react-slick": "0.29.0", "regenerator-runtime": "0.13.11", "rehype-raw": "6.1.1", "sharp": "0.31.3", "slick-carousel": "1.8.1", "styled-components": "5.3.6", "swiper": "^8.4.5", "tslib": "2.4.1" }, "devDependencies": { "@next/eslint-plugin-next": "12.2.2", "@nrwl/cli": "15.4.3-beta.2", "@nrwl/cypress": "15.4.3-beta.2", "@nrwl/eslint-plugin-nx": "15.4.3-beta.2", "@nrwl/express": "15.4.3-beta.2", "@nrwl/jest": "15.4.3-beta.2", "@nrwl/linter": "15.4.3-beta.2", "@nrwl/node": "15.4.3-beta.2", "@nrwl/nx-cloud": "15.0.2", "@nrwl/react": "15.4.3-beta.2", "@nrwl/web": "15.4.3-beta.2", "@nrwl/workspace": "15.4.3-beta.2", "@testing-library/jest-dom": "^5.16.4", "@testing-library/react": "13.4.0", "@testing-library/react-hooks": "8.0.1", "@testing-library/user-event": "^14.3.0", "@types/crypto-js": "4.1.1", "@types/enzyme": "3.10.12", "@types/express": "4.17.15", "@types/jest": "^28.1.8", "@types/node": "18.11.17", "@types/react": "18.0.26", "@types/react-dom": "18.0.10", "@types/react-html-parser": "^2.0.2", "@types/react-slick": "0.23.10", "@typescript-eslint/eslint-plugin": "5.46.1", "@typescript-eslint/parser": "5.46.1", "@zarconontol/enzyme-adapter-react-18": "0.7.3", "babel-jest": "28.1.3", "cypress": "8.7.0", "enzyme": "3.11.0", "enzyme-to-json": "3.6.2", "eslint": "8.30.0", "eslint-config-next": "13.0.0", "eslint-config-prettier": "8.5.0", "eslint-plugin-cypress": "2.12.1", "eslint-plugin-import": "2.26.0", "eslint-plugin-jsx-a11y": "6.6.1", "eslint-plugin-react": "7.31.11", "eslint-plugin-react-hooks": "4.6.0", "glob": "7.2.3", "jest": "28.1.3", "jest-environment-jsdom": "^29.3.1", "jest-svg-transformer": "1.0.0", "nx": "15.4.3-beta.2", "prettier": "2.8.1", "react-test-renderer": "18.0.0", "sass": "1.55.0", "ts-jest": "28.0.8", "ts-node": "10.9.1", "typescript": "4.9.4" } And the problem are:

npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve npm ERR! npm ERR! While resolving: @testing-library/react-hooks@8.0.1 npm ERR! Found: @types/react@18.0.26 npm ERR! node_modules/@types/react npm ERR! dev @types/react@"18.0.26" from the root project npm ERR! @types/react@"*" from @types/enzyme@3.10.12 npm ERR! node_modules/@types/enzyme npm ERR! dev @types/enzyme@"3.10.12" from the root project npm ERR! 4 more (@types/react-dom, @types/react-html-parser, ...) npm ERR! npm ERR! Could not resolve dependency: npm ERR! peerOptional @types/react@"^16.9.0 || ^17.0.0" from @testing-library/react-hooks@8.0.1 npm ERR! node_modules/@testing-library/react-hooks npm ERR! dev @testing-library/react-hooks@"8.0.1" from the root project npm ERR! npm ERR! Conflicting peer dependency: @types/react@17.0.52 npm ERR! node_modules/@types/react npm ERR! peerOptional @types/react@"^16.9.0 || ^17.0.0" from @testing-library/react-hooks@8.0.1 npm ERR! node_modules/@testing-library/react-hooks npm ERR! dev @testing-library/react-hooks@"8.0.1" from the root project npm ERR! npm ERR! Fix the upstream dependency conflict, or retry npm ERR! this command with --force, or --legacy-peer-deps npm ERR! to accept an incorrect (and potentially broken) dependency resolution.

any idea how to resolve this, help god please!

ljharb commented 1 year ago

@mauricioross the error is that you’re using testing library react hooks, which requires react 16 or 17 only, and react 18. You either have to downgrade react, or upgrade to a version of the react hooks testing library package that supports react 18.

sorinpav commented 10 months ago

@ljharb Surely this can't be the accepted solution - to downgrade React? We have the latest available version of @testing-library/react-hooks and still get that error.

Has anyone else looked into this? I really believe this should not be closed as there isn't an acceptable solution given yet.

ljharb commented 10 months ago

If the latest version of RTL doesn’t say it’s compatible with react 18 (which i doubt) then the only solution is for that package to declare compatibility with react 18. Are you sure there’s not a later version?

flemton commented 1 week ago

For anyone coming from a web search, in this thread ljharb suggested installing an older version of react-test-renderer that's actually compatible w/ the issue creator's project's version of react by installing react-test-renderer@16 as a dev dep. So basically, you should run this command:

npm i react-test-renderer@SOME_VERSION --save-dev where SOME_VERSION is the general version of react that you're using in your project.

For instance, in my project I have react version 16.13.1 installed as listed on my package.json. So for me the command would be:

npm i react-test-renderer@16.13 --save-dev

For me that fixed my issue with installing react-test-renderer & I was able to properly install it.

Edit: you might want to also edit the semantic version for react-test-renderer in your package.json so that's its a fixed version (e.g. "^16.13.1" => "16.13.1"). So that way the exact version you want always gets installed. Or better yet, use a ~ like ~16.13.1, which at least allows for minor patches.

This was what fixed mine, simply installing npm i --save-dev react-test-renderer@18.2 fixed my issue and I was able to proceed to install testing-library and other dependencies