Skip to content

chore: upgrade Angular 16 → 21 (latest)#16

Open
devin-ai-integration[bot] wants to merge 7 commits into
mainfrom
devin/1777560857-upgrade-angular-latest
Open

chore: upgrade Angular 16 → 21 (latest)#16
devin-ai-integration[bot] wants to merge 7 commits into
mainfrom
devin/1777560857-upgrade-angular-latest

Conversation

@devin-ai-integration
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot commented Apr 30, 2026

Summary

Upgrades the Angular PetClinic app from Angular 16.2.1 to Angular 21.2.11 (latest), stepping through each major version (16→17→18→19→20→21) using official ng update schematics. All breaking changes have been resolved and the app builds and lints cleanly.

Key changes

Aspect Before After
Angular 16.2.1 21.2.11
TypeScript 4.9.5 5.9.3
RxJS 6.x 7.x
Node.js 18 22+
Build system Webpack (browser) esbuild (application)
Template syntax *ngIf / *ngFor @if / @for
DI pattern Constructor injection inject() function
HTTP setup HttpClientModule provideHttpClient()

Breaking changes handled

  • Build system migration: browserapplication builder (esbuild)
  • Moment.js imports: Namespace imports → default imports for esbuild compatibility
  • HttpClientModule → provideHttpClient(): Deprecated module replaced with functional API
  • Bootstrap glyphicon font conflict: Synced duplicate font files for esbuild output
  • Standalone default change (v19): Explicit standalone: false added to all NgModule-based components
  • Node.js 20+ requirement (v20): Upgraded from Node 18
  • moduleResolution: bundler (v20): Updated tsconfig for esbuild compatibility
  • TestBed.get() → TestBed.inject() (v20): Removed deprecated test API
  • Template control flow (v20): All 19 templates migrated from *ngIf/*ngFor to @if/@for
  • provideZoneChangeDetection() (v21): Bootstrap options migrated to providers
  • Constructor DI → inject(): Migrated all 27 services/components to inject() function
  • Deprecated deps removed: codelyzer, protractor, core-js, karma-coverage-istanbul-reporter

Full details in BREAKING_CHANGES.md.

Review & Testing Checklist for Human

  • Run npm install && npx ng build locally to verify the build succeeds on your environment
  • Verify Node.js 20+ or 22+ is available in your CI/deployment pipeline (Angular 20+ requires it)
  • Spot-check template migrations in a few HTML files (e.g., owner-list.component.html) to confirm @if/@for syntax is correct
  • If you have a backend (spring-petclinic-rest), run the app end-to-end to verify HTTP calls still work with provideHttpClient()
  • Review BREAKING_CHANGES.md for completeness

Notes

  • The app still uses NgModules (not fully standalone). The @angular-eslint/prefer-standalone rule is disabled since a full standalone migration is a separate effort.
  • Bootstrap 3, jQuery, and Tether remain as dependencies — upgrading these is out of scope for this Angular upgrade.
  • The polyfills.ts file still exists on disk but is no longer referenced by angular.json (polyfills are now ["zone.js"]).

Link to Devin session: https://partner-workshops.devinenterprise.com/sessions/a97c861fddb84e01a556bde7e1c55145


Open in Devin Review

- @angular/core, @angular/cli, @angular/material → 17.x
- TypeScript 4.9.5 → 5.4.5
- RxJS 6.x → 7.x
- zone.js 0.13 → 0.14
- @angular-eslint/* → 17.x
- @typescript-eslint/* → 7.x
- angular.json deprecated options updated by migration
- @angular/core, @angular/cli, @angular/material → 18.x
- Migrated from 'browser' to 'application' builder (esbuild)
- HttpClientModule replaced with provideHttpClient() (automated migration)
- Fixed moment.js namespace imports to default imports (esbuild compat)
- Synced Bootstrap glyphicon fonts to fix duplicate output file error
- esModuleInterop enabled in tsconfig.json
- @angular/core, @angular/cli, @angular/material → 19.x
- TypeScript 5.4.5 → 5.8.3
- zone.js 0.14 → 0.15
- @angular-eslint/* → 19.x
- All components explicitly marked standalone: false (Angular 19 default change)
- Standalone is now default in Angular 19
- @angular/core, @angular/cli, @angular/material → 20.x
- @angular-eslint/* → 20.x
- Node.js requirement bumped to v20+ (now using Node 22)
- moduleResolution changed from 'node' to 'bundler' in tsconfig.json
- TestBed.get() replaced with TestBed.inject() (deprecated API migration)
- Templates migrated to new control flow syntax (@if, @for, @switch)
- Workspace generation defaults updated for v20 style guide
- @angular/core, @angular/cli, @angular/material → 21.x
- @angular-eslint/* → 21.x
- TypeScript 5.8.3 → 5.9.3
- tsconfig lib updated from es2017 to es2022
- Bootstrap migrated to use provideZoneChangeDetection() in main.ts
- Deprecated bootstrap options migrated to providers
- Removed deprecated deps: codelyzer, protractor, @types/jasminewd2, core-js,
  karma-coverage-istanbul-reporter
- Updated devDependencies: @typescript-eslint/* → 8.x, @types/jasmine → 5.1,
  @types/node → 22.x, jasmine-core → 5.1, karma → 6.4, karma-coverage added
- Replaced polyfills.ts with zone.js direct reference in angular.json
- Removed useDefineForClassFields: false from tsconfig (deprecated in Angular 20+)
- Updated module to es2022 in tsconfig
- Removed protractor e2e project from angular.json
- Removed createDefaultProgram and e2e/tsconfig.json from .eslintrc.json
- Replaced deprecated @typescript-eslint/quotes with built-in quotes rule
- Migrated constructor injection to inject() function (Angular 21 best practice)
- Removed backwards-compatible constructor overloads
- All lint checks pass
@devin-ai-integration
Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Copy link
Copy Markdown
Contributor Author

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment on lines +70 to +77
} @if (description.dirty && description.hasError('maxlength')) {
<span class="help-block">Description may be at most 255 charaters long</span>
}
@if (description.dirty && description.hasError('maxlength')) {
<span class="help-block">Description may be at most 255 characters long</span>
} @if (description.dirty && description.hasError('maxlength')) {
<span class="help-block">Description may be at most 255 charaters long</span>
}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Duplicate maxlength validation messages with typos in visit-edit template

The *ngIf to @if migration preserved pre-existing duplicate maxlength validation blocks for the description field. When a user triggers the maxlength error, three error messages are displayed instead of one: two with the misspelling "charaters" (lines 71, 76) and one with correct spelling (line 74). The old code had these duplicates crammed onto single lines (which was already buggy), and the migration mechanically converted each *ngIf span into a separate @if block, making the duplication explicit. Only one @if block for maxlength should remain, with the correct spelling "characters".

Suggested change
} @if (description.dirty && description.hasError('maxlength')) {
<span class="help-block">Description may be at most 255 charaters long</span>
}
@if (description.dirty && description.hasError('maxlength')) {
<span class="help-block">Description may be at most 255 characters long</span>
} @if (description.dirty && description.hasError('maxlength')) {
<span class="help-block">Description may be at most 255 charaters long</span>
}
}
@if (description.dirty && description.hasError('maxlength')) {
<span class="help-block">Description may be at most 255 characters long</span>
}
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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.

0 participants