pnpm: PNPM is incorrectly providing the same dependency version to multiple packages relying on different versions

pnpm version: 7.8.0

Code to reproduce the issue:

Attached is a very basic project with two packages, each relying on only a single devDependency (jest) - but each package has a different version of that same dependency. I have added a script jest-version which just logs the jest version for ease of use.

pnpm-dependency-issue.zip

Package-1 - package.json:

  "name": "package-1",
  "version": "1.0.0",
  "description": "Package 1",
  "license": "UNLICENSED",
  "scripts": {
    "jest-version": "jest --version"
  },
  "devDependencies": {
    "jest": "^27.5.1"
  }
}

Package-2 - package.json:

  "name": "package-2",
  "version": "1.0.0",
  "description": "Package 2",
  "license": "UNLICENSED",
  "scripts": {
    "jest-version": "jest --version"
  },
  "devDependencies": {
    "jest": "^24.8.0"
  }
}

Expected behaviour:

I would expect when running pnpm jest-version in package-1 I would get an output of 27.5.1, and when running pnpm jest-version in package-2 I would get an output of 24.8.0.

Actual behaviour:

I get an output of 24.8.0 for the command in both packages.

Additional information:

  • node -v prints: v16.16.0
  • Windows, macOS, or Linux?: Windows and macOS.

For what its worth, this does behave expected on npm (8.11.0).

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 6
  • Comments: 33 (13 by maintainers)

Commits related to this issue

Most upvoted comments

@ConcernedHobbit does this help with the types issue #5176 (comment)?

Dang, @types/react is breaking again. The weird error message may be a clue to what’s going wrong. To recap, the project has two packages, one of which uses @types/react@18 and one uses @types/react@17. With any combination of hoist=false, public-hoist-pattern=[], public-hoist-pattern[]=typesetc.,tsc` fails with a weird import:

(this is in the package which has @types/react@^17)

Type 'React.ReactNode' is not assignable to type 'import("/home/[redacted-path-to-root-folder]/node_modules/.pnpm/@types+react@18.0.21/node_modules/@types/react/index").ReactNode'.

This might be a tsc issue, but I would still assume that it should work with pnpm out-of-the-box.

If anyone else is hitting this we have a sort of workaround that doesn’t require changing hoist patterns

"jest": "./node_modules/jest/bin/jest.js --colors",
 "test": "./node_modules/jest/bin/jest.js --colors",

This resolves to the right version of jest

This seems to also happen with tsc and multiple @types library versions, with tsc always using the alphabetically first (older) @types library.

I’m unfortunately experiencing a similar problematic behaviour. I don’t think this is an issue with just Jest and hoisting in particular given that this used to work properly before I upgraded to pnpm 7 (in version 6.32.8).

Everything worked as expected before updating, the correct version of Jest was instanced in the expected workspace, but not anymore.

One thing that I noticed is that (in version 7) this only happens after I run pnpm install. If I reinstall Jest manually by uninstalling and reinstalling it (with pnpm i -D jest@version), the next time I run pnpm jest --version it will print the correct version. But as soon as I run pnpm installagain, the wrong version will be printed again.

I cannot reproduce the next dev issue anymore. And I cannot think of a reason why anything would break if I remove NODE_PATH patching. So, I will remove it

I highly recommend turning off public-hoist-pattern[] completely. We had it on for years with a large monorepo and it caused us unbelievable issues because we had phantom @types dependencies that would result in very confusing and non-deterministic typechecking results.

🚢 7.29.3

Right, I was not expecting that the removal of NODE_PATH would break anything as the node_modules/.pnpm/node_modules directory should be looked into by default, when resolving require statements in subdirs of node_modules/.pnpm/. Maybe some pluggable tools use the value of NODE_PATH explicitly.

@zkochan Is there a reason extend-node-path was removed? Before upgrading to v7 I used this to workaround the issue. Now the suggested fix is to set hoist=false. We have always used the default hoist settings and I always thought pnpm was strict by default when it came to dependencies. What are the downsides to hoist=false?

@boiboif @ConcernedHobbit This issue cost us several days. But in our case it was not an issue with pnpm but with tsc and ts-jest.

More specifically, in certain scenarios tsc traverses up your directory tree. Effectively ignoring whatever you declared in “typeRoots”.

To fix this we had to add “react” to “paths” in tsconfig.json. See:

in v6 in packages/A I run pnpm jest --version and see the version from packages/A/package.json - 28, with pnpm 7 I do the same and get another version - 26.6.3 (which is probably from packages/B package.json)

I checked packages/A/node_modules/.bin/jest and found out there

exec node "$basedir/../../../../nodemodules/.pnpm/jest@28.1.0@types+node@14.17.21/node_modules/jest/bin/jest.js" "$@" which is correct 🙂 and if I run this command manually in my terminal from the packages/A/node_modules/.bin folder, it works as expected - prints version 28

the main diff I found is in this line export NODE_PATH="/Users/uhavenchyk/p/my-project/node_modules/.pnpm/node_modules" from the packages/A/node_modules/.bin/jest in v7, in v6 it’s a way longer

Looks like it is some issue with Jest, when hoisting is used.

Add this .npmrc to the root of your workspace:

hoist=false

Run pnpm install and it works fine.