packages with peerDependencies are incorrectly hoisted

What I Wanted to Do

Install a package C, with two dependencies A and B, where A has a peerDependency on B, in into a project which has already another version of B hoisted to root node_modules, but no version of A.

Package A should be able to access the correct version of B via require(). It should not get the other hoisted version of B.

In the real case C = webpack, A = acorn-dynamic-import, B = acorn. acorn-dynamic-import contains a require("acorn").

What Happened Instead

npm hoisted package A to root node_modules, where the wrong version of package B is.

Example: C has A@2 and B@2. The project already contains B@1.

This results in this directory structure:

node_modules
  C
    node_modules
      B@2
  A@2
  B@1

In this structure any require("B") in package A results in the wrong module loaded.

Reproduction Steps

Here is a minimal example with https://github.com/sokra/npm-bug-peer-dependencies

Run: npm i

Note that I used file: dependency for a smaller example, but the problem is not related to it. You can replace file:package with "webpack": "4.29.0" to get the same results, but it installs more stuff.

Expected structure:

node_modules
  package
    node_modules
      acorn
      acorn-dynamic-import
  acorn

Actual structure:

node_modules
  package
    node_modules
      acorn
  acorn-dynamic-import
  acorn

Details

Yarn behaves correctly.

see also https://github.com/webpack/webpack/issues/8656

Platform Info

$ npm --versions
{ npm: '6.5.0',
  ares: '1.15.0',
  brotli: '1.0.7',
  cldr: '34.0',
  http_parser: '2.8.0',
  icu: '63.1',
  llhttp: '1.0.1',
  modules: '67',
  napi: '3',
  nghttp2: '1.34.0',
  node: '11.7.0',
  openssl: '1.1.0j',
  tz: '2018e',
  unicode: '11.0',
  uv: '1.24.1',
  v8: '7.0.276.38-node.16',
  zlib: '1.2.11' }
$ node -p process.platform
win32

This is a known issue and, unfortunately, something we won’t be able to fix until we get through an upcoming tree builder rewrite. peerDeps require a bit of extra attention to get right, and the current installer architecture can’t support this (this has been a known bug since npm@3!)

Link to a same issue: Failed to install eslint in a specific situation

I tried to fix this bug myself: https://github.com/npm/cli/pull/147

3 Likes

Thank you! We’ll get you a review soon and make sure this doesn’t run into any other weird corner cases or anything. I appreciate you taking the time to do this. :pray:

This has been fixed.

EDIT: Fix has be reverted: https://github.com/npm/cli/pull/152

2 Likes

this has been on my list of things to raise for quite a while, but haven’t followed through. thank you so much for pushing a fix through :tada:

1 Like

Is the fix released here? We are experiencing hard issue on all our documentation, see:




@kopax the fix was reverted

Any movement here? Far as I know this is still the root cause of https://github.com/webpack/webpack/issues/8656 which is not a minor thing - it’s affecting a lot of projects.

Any updates on fixes to peerDependency hoisting?

at the very least it’d be good to see what the progress is on the tree builder rewrite

This is the root cause of a long living issue of ESLint as well.