Skip to content
This repository has been archived by the owner on Jan 20, 2022. It is now read-only.

ERESOLVE in force mode #180

Closed
isaacs opened this issue Nov 11, 2020 · 5 comments
Closed

ERESOLVE in force mode #180

isaacs opened this issue Nov 11, 2020 · 5 comments

Comments

@isaacs
Copy link
Contributor

isaacs commented Nov 11, 2020

This shouldn't happen.

{
  "devDependencies": {
    "webpack-dev-server": "^3.11.0",
    "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3"
  }
}

npm/cli#2123

@billyjanitsch
Copy link

One note: the package.json you have there actually demonstrates two distinct things.

In theory, npm should be able to install a valid tree here. Namely, webpack@4 is compatible with all of the peer requirements, including transitive ones. (Sure enough, if you add "webpack": "^4.0.0" to the package.json, the install completes without error.) This seems like a potentially-unrelated bug in npm's ability to search for valid resolutions of peer constraints?

But there's also the case where there isn't a valid resolution, such as:

{
  "devDependencies": {
    "webpack-dev-server": "^3.11.0",
    "webpack": "^5.0.0"
  }
}

This is the case that I intended to point out in npm/cli#2123.

Both cases demonstrate the issue with --force, but I just wanted to make sure that this doesn't get conflated with the fact that there actually happens to be a valid resolution for your package.json.

@isaacs
Copy link
Contributor Author

isaacs commented Nov 11, 2020

Thanks! Yes, both should work with --force, and the first should resolve without needing it.

@isaacs
Copy link
Contributor Author

isaacs commented Nov 11, 2020

Ah, so this is interesting. Two factors at play here.

First of all, webpack 5 peer-depends on terser-webpack-plugin@^5.0.3 which peer depends on webpack@^5.1.0. So, when we attempt to check if we can replace webpack@5.4.0 with webpack@4.44.2, we check to see if webpack@4.44.2 would satisfy all the deps on webpack@5.4.0, and find terser-webpack-plugin there depending on it. This of course should be a non-issue, because terser-webpack-plugin would be gone if we replaced webpack 5.4.0 with 4.44.2.

That would normally be fine, especially in --force mode, at least for the first place we try to put it, because that would typically be the peerSetSource (ie, the thing that depends on the thing that is bringing in all these peer deps). Essentially, we always prioritize having a peer set nested under its source dependent, because that is literally the only place it can go, so anything deduped up to that level gets booted and re-parented deeper in the tree.

However, in this case, the peerSetSource also itself has a peer dep on webpack, so we start the search further up the tree (since a peer cannot be nested under its peer dependent.)

Because of this extra second hiccup, we don't go into the more aggressive overriding code path (since we assume we don't have to, since we're just looking for an optimization anyway).

A solution here may be to give the first place we look the special treatment, if we have skipped past the peerSetSource.

Investigating.

@billyjanitsch
Copy link

First of all, webpack 5 peer-depends on terser-webpack-plugin@^5.0.3

Minor correction: webpack@5 directly- (not peer-) depends on terser-webpack-plugin@^5.0.3.

@isaacs
Copy link
Contributor Author

isaacs commented Nov 12, 2020

Ah, ok. Well, same effect :) There's a thing that's holding webpack@5 in place, but we shouldn't care.

Got a fix for it by gathering the dep set when we check for replaceability, but now getting some extraneous metadeps left behind. Should have a fix ready for Friday's npm release, most likely.

isaacs added a commit that referenced this issue Nov 12, 2020
Discovered an interesting issue with the following dependency set:

```json
{
  "devDependencies": {
    "webpack-dev-server": "^3.11.0",
    "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3"
  }
}
```

`webpack-dev-server` here has a peerDependency on webpack v4.  But, the
dependencies of `@pmmmwh/react-refresh-webpack-plugin` have peer
dependencies on webpack at `4 || 5`.

So, a resolution _should_ be possible.  Since the
`@pmmmwh/react-refresh-webpack-plugin` package is alphabetically first,
it loads its deps, and ends up placing webpack@5 to satisfy the dep with
the latest and greatest.  Then when `webpack-dev-server` gets to its
eventual peer dep on webpack, it can't replace it, because `webpack@5`
has a dependency on `terser-webpack-plugin@^5.0.3`, which in turn has a
peer dependency on `webpack@5.4.0`.

When we check to see if webpack 5 can be replaced, we find it has a
dependent, and reject the replacement.  But that dependent is only
present as a dependency of the thing being replaced, so should not be
considered.

Second, while the source of the `terser-webpack-plugin` is `webpack`, it
cannot be installed there, because it has peer deps that are also peer
deps of webpack.  So, we _must_ place it in the root node_modules, but
were not attempting the "source" location overrides, because the root is
not the source.  This was a second issue resulting in `ERESOLVE` errors
even when `--force` was applied.

Fixes: #180
Fixes: npm/cli#2123
isaacs added a commit that referenced this issue Nov 12, 2020
Discovered an interesting issue with the following dependency set:

```json
{
  "devDependencies": {
    "webpack-dev-server": "^3.11.0",
    "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3"
  }
}
```

`webpack-dev-server` here has a peerDependency on webpack v4.  But, the
dependencies of `@pmmmwh/react-refresh-webpack-plugin` have peer
dependencies on webpack at `4 || 5`.

So, a resolution _should_ be possible.  Since the
`@pmmmwh/react-refresh-webpack-plugin` package is alphabetically first,
it loads its deps, and ends up placing webpack@5 to satisfy the dep with
the latest and greatest.  Then when `webpack-dev-server` gets to its
eventual peer dep on webpack, it can't replace it, because `webpack@5`
has a dependency on `terser-webpack-plugin@^5.0.3`, which in turn has a
peer dependency on `webpack@5.4.0`.

When we check to see if webpack 5 can be replaced, we find it has a
dependent, and reject the replacement.  But that dependent is only
present as a dependency of the thing being replaced, so should not be
considered.

Second, while the source of the `terser-webpack-plugin` is `webpack`, it
cannot be installed there, because it has peer deps that are also peer
deps of webpack.  So, we _must_ place it in the root node_modules, but
were not attempting the "source" location overrides, because the root is
not the source.  This was a second issue resulting in `ERESOLVE` errors
even when `--force` was applied, with this dependency set:

```json
{
  "devDependencies": {
    "webpack-dev-server": "^3.11.0",
    "webpack": "^5.0.0"
  }
}
```

Fixes: #180
Fixes: npm/cli#2123
isaacs added a commit that referenced this issue Nov 13, 2020
Discovered an interesting issue with the following dependency set:

```json
{
  "devDependencies": {
    "webpack-dev-server": "^3.11.0",
    "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3"
  }
}
```

`webpack-dev-server` here has a peerDependency on webpack v4.  But, the
dependencies of `@pmmmwh/react-refresh-webpack-plugin` have peer
dependencies on webpack at `4 || 5`.

So, a resolution _should_ be possible.  Since the
`@pmmmwh/react-refresh-webpack-plugin` package is alphabetically first,
it loads its deps, and ends up placing webpack@5 to satisfy the dep with
the latest and greatest.  Then when `webpack-dev-server` gets to its
eventual peer dep on webpack, it can't replace it, because `webpack@5`
has a dependency on `terser-webpack-plugin@^5.0.3`, which in turn has a
peer dependency on `webpack@5.4.0`.

When we check to see if webpack 5 can be replaced, we find it has a
dependent, and reject the replacement.  But that dependent is only
present as a dependency of the thing being replaced, so should not be
considered.

Second, while the source of the `terser-webpack-plugin` is `webpack`, it
cannot be installed there, because it has peer deps that are also peer
deps of webpack.  So, we _must_ place it in the root node_modules, but
were not attempting the "source" location overrides, because the root is
not the source.  This was a second issue resulting in `ERESOLVE` errors
even when `--force` was applied, with this dependency set:

```json
{
  "devDependencies": {
    "webpack-dev-server": "^3.11.0",
    "webpack": "^5.0.0"
  }
}
```

Fixes: #180
Fixes: npm/cli#2123

PR-URL: https://github.com/pull/182
Credit: @isaacs
Close: #182
Reviewed-by: @darcyclarke
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants