Skip to content

fix(angular): accept Angular 20, 21 and 22 as peers - #463

Open
AminDhouib wants to merge 2 commits into
devfrom
fix/angular-peer-range
Open

AminDhouib wants to merge 2 commits into
devfrom
fix/angular-peer-range

Conversation

@AminDhouib

Copy link
Copy Markdown
Member

Why

@useupup/angular@3.3.3 declares @angular/core and @angular/common as ^19.0.0 only. Angular's latest tag is 22.2.0, with 20 and 21 on LTS. So anyone following the Angular quickstart on a current Angular app fails at the first command:

npm install @angular/core@22 @angular/common@22 rxjs@7 @useupup/angular@3.3.3
npm error ERESOLVE unable to resolve dependency tree

The same happens on Angular 20.3.32. Both were reproduced on npm 11.19 / Node 24.21.

The package itself was never the problem. The published 3.3.3 was forced in with --legacy-peer-deps on 20.3.32, 21.2.24 and 22.2.0 (TS 6.0.3). On all three it passed:

  • a production AOT build;
  • a library build with skipLibCheck: false and strictTemplates. A deliberate TS2322 proves the .d.ts really was checked.
  • a headless Chromium run that renders, adds a file and fails an upload, firing (filesAdded) and (error). Its DOM matches the Angular 19 control at every state.

Both zone and zoneless were covered: 21 and 22 scaffold zoneless by default, and both ends were cross-tested.

What changed

  1. fix(angular): accept Angular 20, 21 and 22 as peers
    • @angular/core and @angular/common become ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0.
    • @angular/platform-browser is added as a peer with the same range. The FESM already imports DomSanitizer from it without declaring it.
    • rxjs stays ^7.8.0, and the ^19 dev toolchain is unchanged.
    • The range is deliberately not >=19, because 23 is unproven.
    • The package description, README, Angular quickstart, framework-guide note, FAQ and agent-setup detection rule now say 19–22. The detection rule said 17+, which never installed.
    • A new peer-dependency-range.spec.ts pins that all three @angular/* peers accept 19.0.0, 20.0.0, 21.0.0 and 22.0.0.
      • It carries a small caret-range checker, since the workspace has no semver dependency.
      • The checker throws on any range syntax it doesn't model, so a rewrite of the range can't pass silently.
      • It reads package.json through a JSON import, so tsconfig.spec.json enables resolveJsonModule.
    • A patch changeset.
  2. docs(landing): quickstarts hub lists Angular 19–22

RED against the old ^19-only package.json, from vitest run src/peer-dependency-range.spec.ts (exit 1):

× declares @angular/core as a peer that accepts Angular 19, 20, 21 and 22
× declares @angular/common as a peer that accepts Angular 19, 20, 21 and 22
× declares @angular/platform-browser as a peer that accepts Angular 19, 20, 21 and 22
AssertionError: @angular/core peer range "^19.0.0": expected [ '20.0.0', '21.0.0', '22.0.0' ] to deeply equal []
AssertionError: @angular/platform-browser is missing from peerDependencies: expected undefined to deeply equal Any<String>
      Tests  3 failed | 2 passed (5)

GREEN: 5/5. The full Angular suite passes 276/276.

Checks

All were run on the build host and exited 0:

  • pnpm install --frozen-lockfile; pnpm-lock.yaml is unchanged.
  • The Angular build. Its dist/package.json carries all four peers.
  • Root pnpm run typecheck (31/31) and Angular lint.
  • Landing: lint and vitest (254/254).
  • prettier --check on every touched file, and prettier-check.
  • vocab:check and test:quality (run after git add).
  • knip.
  • docs:links:check: 529 links across 72 pages.
  • changeset status.
  • smoke:packages: the packed Angular tarball has the widened peers and @useupup/core pinned to 3.3.3, with no workspace:* left.

Fresh Angular apps were scaffolded on a second host, and the smoke tarballs were installed with a plain npm install:

Angular published 3.3.3 this branch ng build
22.2.0 ERESOLVE (exit 1) exit 0, one @angular/core@22.2.0 exit 0
20.3.32 ERESOLVE (exit 1) exit 0, one @angular/core@20.3.32 exit 0

Notes

  • This touches packages/, so it routes the MinIO suite. That suite is blocked on the GHCR image pull (fix(ci): pull MinIO images from the org's GHCR mirror #437), so this PR waits behind it.
  • .changeset/config.json puts all nine packages in one fixed group. The release that ships this bumps all nine to 3.3.4, including @useupup/server, whose trusted-publisher setup still needs a maintainer's npm passkey before it can publish.

@useupup/angular declared @angular/core and @angular/common as ^19.0.0
only, so npm refused to install it on Angular 20+ with ERESOLVE. A spike
on the published 3.3.3 showed that only the range was wrong. Forced in
with --legacy-peer-deps, the package passed a production AOT build, a
build with skipLibCheck:false and strictTemplates, and a headless render
with a file add and a failed upload on 20.3.32, 21.2.24 and 22.2.0, in
both zone and zoneless mode. Its DOM matched the Angular 19 control.

- peerDependencies: @angular/core and @angular/common become
  ^19.0.0 || ^20.0.0 || ^21.0.0 || ^22.0.0. @angular/platform-browser is
  added with the same range, because the FESM imports DomSanitizer from it
  without declaring it. rxjs stays ^7.8.0, and the ^19 dev toolchain is
  unchanged.
- The description, the README, the Angular quickstart, the framework
  guide note and FAQ, and the agent-setup detection rule now say 19–22.
  The detection rule said 17+, which never installed.
- peer-dependency-range.spec.ts pins that all three @angular/* peers
  accept 19.0.0, 20.0.0, 21.0.0 and 22.0.0. It reads package.json through
  a JSON import, so tsconfig.spec.json enables resolveJsonModule. The
  workspace has no semver dependency, so the spec carries a small caret
  checker. The checker throws on any range syntax it does not model.

RED against the old ^19-only package.json (vitest run
src/peer-dependency-range.spec.ts, exit 1):

 ❯ src/peer-dependency-range.spec.ts (5 tests | 3 failed) 17ms
     ✓ accepts versions inside a caret alternative and rejects other majors 3ms
     ✓ throws on range syntax it does not model instead of passing 1ms
     × declares @angular/core as a peer that accepts Angular 19, 20, 21 and 22 7ms
     × declares @angular/common as a peer that accepts Angular 19, 20, 21 and 22 2ms
     × declares @angular/platform-browser as a peer that accepts Angular 19, 20, 21 and 22 1ms
AssertionError: @angular/core peer range "^19.0.0": expected [ '20.0.0', '21.0.0', '22.0.0' ] to deeply equal []
AssertionError: @angular/common peer range "^19.0.0": expected [ '20.0.0', '21.0.0', '22.0.0' ] to deeply equal []
AssertionError: @angular/platform-browser is missing from peerDependencies: expected undefined to deeply equal Any<String>
      Tests  3 failed | 2 passed (5)

GREEN after the change: 5 passed (5); the full angular suite has 276 passed
(20 files).
The quickstarts hub from #460 described @useupup/angular as a component
for Angular 19 apps. With the peer range widened, it supports 19 through
22, matching the Angular quickstart, the README and the FAQ.
@codesandbox

codesandbox Bot commented Sep 27, 2026

Copy link
Copy Markdown

Review or Edit in CodeSandbox

Open the branch in Web Editor • VS Code • Insiders

Open Preview

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant