Files
Leosvel Pérez Espinosa b53ba26488 feat(angular): add support for Angular v22.1 (#36521)
## Current Behavior

Nx pins Angular 22.0.x, so new workspaces are scaffolded on the previous
minor and `nx migrate` leaves existing ones there.

## Expected Behavior

Nx supports Angular 22.1. New workspaces are scaffolded on it, and `nx
migrate` moves existing 22.0.x workspaces across.

The versions Nx prescribes (`versions.ts`, `angularCliVersion`, and the
`packageJsonUpdates` groups) use `~22.1.0`, and `~0.2201.0` for
`@angular-devkit/architect`. The workspace's own `catalogs.angular`
moves to the same ranges. angular-eslint moves to `^22.1.0`, with the
paired `-angular-eslint` and `-@angular-eslint` groups raising the floor
for existing workspaces.

`catalogs.angular-supported-versions` is unchanged; a minor does not
shift the supported window. Its lockfile resolutions do move to the new
versions. A range left behind on the old ones puts two copies of
`@angular-devkit/core` and `@angular-devkit/architect` into
`@nx/angular`'s type graph, and the build then fails with TS2345 because
the two `BuilderContext` types are not assignable to each other.

> [!WARNING]
> Cypress component testing does not work on Angular 22. Cypress warns
that the installed dependency versions aren't officially supported when
component testing starts, so problems are expected across the whole
major. On 22.1.0 that turns into a hard failure: Cypress compiles
component tests with `@angular-devkit/build-angular`, which moved to
Babel 8 in 22.1.0, and it cannot load the Babel 8 packages, so every
module fails to build and no spec runs.
>
> The Angular component testing generators now refuse to run that
combination instead of scaffolding a setup that cannot execute.
`cypress-component-configuration` and `component-test` throw when the
workspace is on Angular 22.1 or higher and Cypress is below 16, the
release expected to support it. The check reads the versions declared in
the workspace `package.json`, falls back to the Cypress version the
generator would install when Cypress is absent, and stays quiet when
either package is missing or pinned to a dist tag. Workspaces migrated
to 22.1 with component testing already configured aren't covered by it;
there the failure still surfaces when the component test target runs.
>
> The fix is tracked in
https://github.com/cypress-io/cypress/issues/34461, and the Angular
component testing e2e suites are skipped until it lands.

## Implementation Details

The v22.1 changelogs were reviewed for anything Nx has to mirror, and
there was nothing:

- The Angular builder `schema.json` files are byte-identical between
v22.0.4 and v22.1.2, so no executor schema needs updating.
- `migration-collection.json` is unchanged, so there are no new
migrations to port.
- `@angular/build`'s `private.ts` export surface is unchanged, and every
module `@nx/angular-rspack` and `@nx/angular-rspack-compiler` import
from it is still exported.
- Every ng-packagr module Nx imports is unchanged between 22.0.0 and
22.1.1. The internal fixes in that range (stylesheet bundler
concurrency, cache handling) sit behind the classes Nx subclasses, so
they come along with the bump.

The bump does force changes outside the version files:

- The Angular mixed component testing and e2e test in
`e2e/cypress/src/cypress.test.ts` is skipped alongside the Angular
component testing suites, since the generator it drives now throws. The
equivalent Next.js test keeps running. The one assertion the skipped
suites carried that nothing else does, the missing build configuration
error, moves into the generator spec.
- Jest maps `magic-string` to a shim over the workspace's 0.30.x
CommonJS build. `@angular-devkit/schematics@22.1` pulls
`magic-string@1`, which is ESM-only, and 0.30.x's CommonJS module object
is the class itself with no named `MagicString` export, which is the
binding schematics 22.1 reads. The shim serves both that and the default
export the 22.0 line and our own `file-change-recorder` use.
- ng-packagr resolves to 22.1.1 rather than 22.1.0. 22.1.0 depends on
`rollup-plugin-dts: ^6.4.0`, which now resolves to 6.5.0, and 6.5.0
requires the ESM-only `magic-string@1`, so ng-packagr's CommonJS build
throws `MagicString is not a constructor` on every Angular library
build. 22.1.1 pins `~6.4.1`, and that range is the only difference
between the two releases.

Reconciling the lockfile also drops a set of duplicate resolutions,
including the second `@angular-devkit/core`,
`@angular-devkit/schematics` and `@angular-devkit/architect` copies that
`angular-eslint`'s own devkit ranges had held on an older patch. Nothing
moves to a different version; the entries are only removed.

Two unrelated fixes ride along because the bump touched their
surroundings. `packages/eslint`'s hardcoded angular-eslint fallback
carries a comment asking that it be kept in sync with
`angularEslintVersion`; the fallback is deliberately `^<major>.0.0`, so
the comment now says to keep the major in sync rather than the whole
range. And a generator spec assertion that never ran its own body
(`await expect(async () => {...}).resolves`, which neither invokes the
callback nor applies a matcher) now awaits the generator directly.

Docs get the matching update: a `~22.1.0` row in the Angular version
matrix.

## Related Issue(s)

NXC-4749

<!-- polygraph-session-start -->
---
<p><picture><source media="(prefers-color-scheme: dark)"
srcset="https://static.ops.cloud.nx.app/polygraph/session-logo-v4-dark.svg"><img
src="https://static.ops.cloud.nx.app/polygraph/session-logo-v4-light.svg"
width="16" height="22" align="middle" alt="Polygraph"></picture> <a
href="https://app.trypolygraph.com/orgs/6a061dcb561c062131116eca/sessions/nxc-4749-2ba1d228">View
session ↗</a></p>
<!-- polygraph-session-end -->
2026-08-05 11:05:38 -04:00
..