Skip to content

Update project to Angular v22 - #14

Closed
dimeloper wants to merge 9 commits into
mainfrom
claude/bold-lamport-z8ihf8
Closed

dimeloper wants to merge 9 commits into
mainfrom
claude/bold-lamport-z8ihf8

Conversation

@dimeloper

@dimeloper dimeloper commented Sep 26, 2026 •

Copy link
Copy Markdown
Owner

Summary

Upgrades the project from Angular v19 to v22, one major version per commit (v20 → v21 → v22), applying the official ng update migrations at each step. It then brings the app in line with v22 defaults (zoneless, OnPush, no deprecated APIs), fixes two styling regressions on the optimized pokedex page, and updates server.ts for the Netlify Angular runtime v4.

Changes

Angular upgrade

  • v20 (8ce6fe8): Angular, CDK/Material, NgRx Signals and angular-eslint bumped to v20; Analog 2.x; TypeScript 5.9. Migrations applied (withRoutes, BootstrapContext); resource() request → params. Pinned Node.js bumped to 24.21.0.
  • v21 (735bb44): v21 packages; ngx-device-detector v11 (inject()-based constructor); control flow migration.
  • v22 (f8374a5): v22 packages, TypeScript 6.0, ngx-device-detector v12, angular-eslint flat config package, Vitest 4 / Vite 7; removed @angular/platform-browser-dynamic, @nx/vite, vite-tsconfig-paths.
  • CI (b15d735): PR checks on Node.js 24 and pnpm 10.

Netlify SSR (25baa42)

  • @netlify/angular-runtime bumped to v4. The runtime requires v4 for @angular/ssr 21.2.9+, and v4 removes the @netlify/angular-runtime/context import the old server.ts used.
  • server.ts replaced with the runtime's documented App Engine handler, including allowedHosts and trustProxyHeaders. Netlify deploys this module as a Deno edge function, so it no longer bundles Express or Node-only APIs.
  • Dropped express and the serve:ssr script. That script only served static files, because SSR runs through netlifyAppEngineHandler. ng serve still renders on the server through reqHandler.

v22 alignment

  • Deprecated APIs (8d68814): removed withIncrementalHydration() and withFetch(), which are defaults in v22, plus provideAnimationsAsync() and @angular/animations; Material no longer needs the package. Also removed dead AppComponent click handling: the window listener never ran, and the manual openMenu() call stopped the menu button from closing the menu.
  • Zoneless + OnPush (7c66d28): removed zone.js and the ChangeDetectionStrategy.Eager overrides the migration had added. State that changes outside template bindings (breakpoint observer, form toggles) now uses signals. Tests run on Analog's zoneless TestBed. The initial bundle drops from 669 kB to 626 kB, below the pre-upgrade 640 kB.

UI regressions on /pokedex-optimized

  • Banner covering the page (0b69190): cbc0767 ("Test precommit.") emptied pokedex.component.scss. Without the position: relative, fixed-height .banner container, the fill-mode NgOptimizedImage banner stretched across the whole viewport and hid the toolbar. The styles are restored.
  • Card previews on mobile (46b7587): the rule that hides previews at ≤960px stayed in the page stylesheet when the grid was extracted into BannerGridComponent (a8cad0d, March 2024). View encapsulation kept it from applying. It now lives in the component again.

Verification

Run locally on the final commit:

  • pnpm build, pnpm lint, pnpm format:check: pass.
  • pnpm test: 16 files, 44 tests pass.
  • Browser checks (Playwright against ng serve with SSR, PokéAPI mocked), all 13 pass:
    • /pokedex-optimized renders on the server; the toolbar is visible and not covered; the banner is 480px tall.
    • The menu opens and closes.
    • The deferred Pokémon list loads from the signal store.
    • The inline form and the dialog both open.
    • /pokedex-bad switches to 2 columns and the mobile banner on small screens.
    • /pokemon-optimized/ivysaur renders when opened directly.
    • No runtime or hydration errors.

Still to verify on the Deploy Preview: open an SSR route such as /pokedex-optimized directly. The production edge crash couldn't be reproduced locally: the deployed main bundle renders under Deno 2 with Netlify's built-in import map, so the root cause needs confirming against the Netlify edge function logs.

Follow-ups (not in this PR)

  • Migrate the remaining specs from the deprecated RouterTestingModule to provideRouter().
  • Consider httpResource() in place of the manual fetch-based resource() loaders.
  • Remove the @netlify/angular-runtime "Missing Netlify-specific environment variable" warnings from local builds (expected outside Netlify).

- Bump Angular, CDK/Material, NgRx Signals and angular-eslint to v20.
- Bump Analog vitest integration to v2 and TypeScript to 5.9.
- Apply ng update migrations (SSR withRoutes, BootstrapContext, schematics defaults).
- Migrate resource() usages from request to params.
- Bump pinned Node.js to 24.21.0.
- Bump Angular, CDK/Material, NgRx Signals and angular-eslint to v21.
- Keep zone-based change detection explicit now that zoneless is the default.
- Apply control flow migration to the problematic component.
- Bump ngx-device-detector to v11 and adapt to its inject()-based constructor.
- Bump Angular, CDK/Material, NgRx Signals, ngx-device-detector and angular-eslint to v22.
- Bump TypeScript to 6.0 and typescript-eslint to 8.70.
- Apply ng update migrations (explicit ChangeDetectionStrategy.Eager, extended diagnostics opt-out).
- Move ESLint config to the angular-eslint flat config package.
- Bump Vitest to v4 and Vite to v7; use platform-browser testing APIs.
- Drop deprecated platform-browser-dynamic and unused @nx/vite, vite-tsconfig-paths.
- Update README Angular version.
Angular v22 requires Node.js ^22.22.3 or ^24.15.0.
@warestack

warestack Bot commented Sep 26, 2026

Copy link
Copy Markdown

Warestack Governance Checks

Warestack is installed for this GitHub account, but this installation is not connected to a Warestack space yet.

Get started:

  1. Sign in to Warestack and connect this GitHub installation
  2. Enable governance rules for dimeloper/angular-optimization
  3. The next pull request will receive automated feedback

This message is posted once per new pull request while this installation is not connected.

@netlify

netlify Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for ng-pokedex-optimization ready!

Name Link
🔨 Latest commit 7c66d28
🔍 Latest deploy log https://app.netlify.com/projects/ng-pokedex-optimization/deploys/6ab8014a33f3d00009ad068d
😎 Deploy Preview https://deploy-preview-14--ng-pokedex-optimization.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
Lighthouse
Lighthouse
1 paths audited
Performance: 88
Accessibility: 100
Best Practices: 100
SEO: 100
PWA: -
View the detailed breakdown and full score reports

To edit notification comments on pull requests, go to your Netlify project configuration.

The styles were accidentally emptied in cbc0767. Without the relative,
sized .banner container the fill-mode NgOptimizedImage banner stretched
over the whole viewport and covered the toolbar.
- Bump @netlify/angular-runtime to v4, required for @angular/ssr 22 on Netlify.
- Replace the Express-based server with the runtime's documented App Engine
  handler, since Netlify deploys it as a Deno edge function.
- Configure allowedHosts and trustProxyHeaders via the runtime helpers.
- Drop the unused express dependency and the static-only serve:ssr script.
- Drop withIncrementalHydration() and withFetch(); both are defaults in v22.
- Drop provideAnimationsAsync() and @angular/animations; Material no longer
  depends on the animations package.
- Remove redundant standalone flags and an unused trackBy function.
- Remove the AppComponent window click listener (it never ran, as the
  referenced toggleButton does not exist) and the manual openMenu() call
  that prevented the menu button from closing the menu.
The rule stayed in the page stylesheet when the grid was extracted into
BannerGridComponent (a8cad0d), where view encapsulation prevents it from
reaching the component's cards.
- Remove zone.js and provideZoneChangeDetection(); zoneless change detection
  is the v22 default.
- Drop the ChangeDetectionStrategy.Eager overrides added by the v22 migration
  and re-enable prefer-on-push-component-change-detection.
- Convert state mutated outside template bindings (breakpoint observer,
  form toggles) to signals.
- Use Analog's zoneless TestBed setup, stub IntersectionObserver for
  @defer (on viewport) under jsdom, and replace fakeAsync with whenStable().

Initial bundle drops from 669 kB to 626 kB.
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