`npm install` fails with NPM 7

🐞 Bug report

Command (mark with an x)

  • new
  • build
  • serve
  • test
  • e2e
  • generate
  • add
  • update
  • lint
  • extract-i18n
  • run
  • config
  • help
  • version
  • doc

Is this a regression?

This bug did not occur a couple of days ago. It doesn’t seem like it’s caused by a specific CLI version. It might be caused by some (peer) dependency of a brand-new Angular project which changed its dependencies.

Description

Creating a new Angular project with the Angular CLI (ng new) fails when using the latest version of npm (7.5.x).

Error message see below.

🔬 Minimal Reproduction

  1. Install latest version of Angular CLI: npm install -g @angular/cli@latest
  2. Install latest version of npm: npm install -g npm@latest
  3. Create a new Angular project: ng new some-app

Step 3 crashes with the below error message.

🔥 Exception or Error


npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: ng-npm@0.0.0
npm ERR! Found: @angular/compiler-cli@11.2.0-next.0
npm ERR! node_modules/@angular/compiler-cli
npm ERR!   dev @angular/compiler-cli@"~11.2.0-next.0" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer @angular/compiler-cli@"^11.0.0 || ^11.1.0-next" from @angular-devkit/build-angular@0.1102.0-next.0
npm ERR! node_modules/@angular-devkit/build-angular
npm ERR!   dev @angular-devkit/build-angular@"~0.1102.0-next.0" 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.
npm ERR! 
npm ERR! See /Users/maximilianschwarzmuller/.npm/eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/maximilianschwarzmuller/.npm/_logs/2021-02-03T21_29_25_647Z-debug.log
✖ Package install failed, see above.
The Schematic workflow failed. See above.

🌍 Your Environment


Angular CLI: 11.1.2
Node: 15.4.0
OS: darwin x64

Angular: undefined
... 
Ivy Workspace: 

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.1101.2
@angular-devkit/core         11.1.2
@angular-devkit/schematics   11.1.2
@angular/cli                 11.1.2
@schematics/angular          11.1.2
@schematics/update           0.1101.2

3 thoughts on “`npm install` fails with NPM 7

  1. We talked about this issue in our CLI triage meeting, unfortunately there’s a lot of complexity but we think we have a path forward.

    The most immediate “solution” to this problem is to restrict our engines in package.json to disallow NPM 7. This will warn on npm install that NPM 7 is not supported, and will outright fail if the user uses --engine-strict. We will also add a check in the ng CLI to make this an error even for users who don’t use --engine-strict. I think we already have one for Node, we’ll either need to add one for NPM or confirm that it already has this behavior. This will make ng new, ng update, and ng add fail with clear error on NPM 7. We’ll need to publish this change to all supported CLI versions, since they’ll all have the same problem. It doesn’t really solve the issue, but it will at least give a more actionable error message. I’m also pinning this issue just to raise awareness about it and head off duplicates.

    Regarding the tsickle problem, the clear solutions are to:

    1. Make a new release of tsickle which supports TS >=4.0. We’ll need to coordinate with the relevant people to get this out, but the advantage of this is that it will fix the issue for users in a backward-compatible way, so users don’t need to update their versions to leverage the fix. This already has an issue in angular/tsickle#1242.
    2. Remove tsickle from ng-packagr. This was only used to support Closure compilation, which isn’t supported by the Angular framework anymore anyways, so there’s little value in keeping it around. @alan-agius4 already has a PR to remove it. This will fix future versions of ng-packagr, regardless of what happens to tsickle.

    Regarding the @angular/localize issue: this is a bit more complicated. Packages from Angular framework are published simultaneously, with pinned versions on each other. In this case, @angular/localize@11.1.2 has a pinned peer dep on specifically @angular/compiler@11.1.2. Generally speaking, peer deps are supposed to be as broad as possible, but since all Angular packages are released at once and managed by the Angular CLI, we expect users to fairly consistently use matching package versions. Historically this has been fine because NPM mostly ignored those peer deps, but now it is trying to validate them and running into conflicts.

    While we could unpin FW peer deps to use something like ^11.0.0, that expands a whole swath of possible error states that may arise. Even if we did this going forward, it wouldn’t provide an immediate solution unless we changed all currently supported versions the same way. It’s also important to point out that @angular/localize@11.1.2 was authored with the expectation that it depends on @angular/compiler@11.1.2, so we have no guarantee that it would work if we gave it @angular/compiler@11.0.9. Since this problem applies to all FW packages, an extensive amount of testing and bug fixing would be necessary to make this work. As a result, we don’t think this is a viable option atm.

    Alternatively, this is arguably an NPM 7 bug since there is a solution to dependency resolution which it failed to find. It seems that NPM 7 is picking the latest compatible version of @angular/localize@^11.0.0; that happens to be @angular/localize@11.1.2, which has a peer dep on @angular/compiler@11.1.2, which is incompatible with the @angular/compiler@11.0.9 defined by ng new in the user’s package.json. However, NPM could just pick @angular/localize@11.0.9, which has a pinned peer dep on @angular/compiler@11.0.9 and satisfies all the requirements. It’s not the absolute latest version, but it satisfies all semvers and is probably the right answer. There is an NPM issue about this using different packages but illustrating the same problem. If NPM can address this in their package resolution logic, then we don’t need to change anything and it will “just work”.

    Similarly, @angular/localize (and tsickle) is an optional peer dep which is now being installed by NPM. I’m not sure if this is expected, as the release notes I’ve found don’t seem to mention this case. However, whether it tries to install an optional peer dep or not, it definitely shouldn’t fail because that peer dep couldn’t be resolved, otherwise it isn’t optional. If NPM failed gracefully in these situations, either printing a warning or just carrying on, things would work just fine. There is another NPM issue about this.

    For right now, our plan is to do nothing about the @angular/localize issue and hope NPM fixes it for us. If this is expected behavior on the NPM side, then we can reevaluate what we can do on the Angular side to solve the problem.

  2. Hi @dgp1130 we have been trying to raise awareness that the peer dependencies installation behavior from npm@7 has an opt-out option for projects that are unfortunately running into problems with it.

    While I’m not really familiar with angular-cli it seems to me the reported problem is during the bootstrap of a new project, in that case I would recommend shipping a .npmrc file at the project root level setting legacy-peer-deps=true as a quick way to fix the problem.

    If that’s not really the case, we would really appreciate if the warning message could point users running npm@7 to use the --legacy-peer-deps option instead of recommending users to downgrade to a legacy version.

    Thanks! 😊

  3. Hi @dgp1130 we have been trying to raise awareness that the peer dependencies installation behavior from npm@7 has an opt-out option for projects that are unfortunately running into problems with it.

    While I’m not really familiar with angular-cli it seems to me the reported problem is during the bootstrap of a new project, in that case I would recommend shipping a .npmrc file at the project root level setting legacy-peer-deps=true as a quick way to fix the problem.

    If that’s not really the case, we would really appreciate if the warning message could point users running npm@7 to use the --legacy-peer-deps option instead of recommending users to downgrade to a legacy version.

    Thanks! 😊

    Totally agree with this. NPM explicitly include options to remain legacy behaviour exactly because of this kind of reasons. The .npmrc file could additionally be generated by the CLI for workspaces for new and upgrades just for the time of transition.

    Requiring everyone to downgrade NPM should be the last option to consider, which is not necessary here…

    cheers
    flash