Angular checkup
ang2-conduit
Overview
Top priorities
- HighAngular 12 is 10 majors behind 22 and out of support Angular version & tooling
- HighUnit tests run on Karma, which is deprecated Testing
- HighNo unit tests found Testing
- HighEnd-to-end tests use Protractor, which is end of life Testing
- High
strictNullChecksis off Type safety
Upgrade plan: Angular 12 → 22
10 steps, one major at a time, as ng update requires. Requirements come from each version's published package metadata.
- Move from TSLint to ESLint
ng add @angular-eslint/schematicsTSLint is deprecated and later versions of the Angular CLI no longer support it.
-
→ 13Angular 13.4.0
ng update @angular/core@13 @angular/cli@13Node.js ^12.20.0 || ^14.15.0 || >=16.10.0TypeScript >=4.4.2 <4.7 (now 4.3.5)RxJS ^6.5.3 || ^7.4.0zone.js ~0.11.4
-
→ 14Angular 14.3.0
ng update @angular/core@14 @angular/cli@14Node.js ^14.15.0 || >=16.10.0TypeScript >=4.6.2 <4.9RxJS ^6.5.3 || ^7.4.0zone.js ~0.11.4 || ~0.12.0
-
→ 15Angular 15.2.10
ng update @angular/core@15 @angular/cli@15Node.js ^14.20.0 || ^16.13.0 || >=18.10.0TypeScript >=4.8.2 <5.0RxJS ^6.5.3 || ^7.4.0zone.js ~0.11.4 || ~0.12.0 || ~0.13.0
-
→ 16Angular 16.2.12
ng update @angular/core@16 @angular/cli@16Node.js ^16.14.0 || >=18.10.0TypeScript >=4.9.3 <5.2RxJS ^6.5.3 || ^7.4.0zone.js ~0.13.0 (now 0.11.8)
- Convert NgModule components to standalone 18
ng generate @angular/core:standaloneThree passes: convert declarations, remove unneeded NgModules, switch to standalone bootstrap.
- Convert NgModule components to standalone 18
-
→ 17Angular 17.3.12
ng update @angular/core@17 @angular/cli@17Node.js ^18.13.0 || >=20.9.0TypeScript >=5.2 <5.5RxJS ^6.5.3 || ^7.4.0zone.js ~0.14.0
- Move templates to built-in control flow 13
ng generate @angular/core:control-flow
- Move templates to built-in control flow 13
-
→ 18Angular 18.2.14
ng update @angular/core@18 @angular/cli@18Node.js ^18.19.1 || ^20.11.1 || >=22.0.0TypeScript >=5.4 <5.6RxJS ^6.5.3 || ^7.4.0zone.js ~0.14.10
- Switch to the esbuild application builder 1
ng update @angular/cli --name use-application-builder
- Switch to the esbuild application builder 1
-
→ 19Angular 19.2.25
ng update @angular/core@19 @angular/cli@19Node.js ^18.19.1 || ^20.11.1 || >=22.0.0TypeScript >=5.5 <5.9RxJS ^6.5.3 || ^7.4.0zone.js ~0.15.0
- Convert @Input() and @Output() to signal inputs and outputs 12
ng generate @angular/core:signal-input-migration && ng generate @angular/core:output-migration
- Convert @Input() and @Output() to signal inputs and outputs 12
-
→ 20Angular 20.3.34
ng update @angular/core@20 @angular/cli@20Node.js ^20.19.0 || ^22.12.0 || >=24.0.0TypeScript >=5.8 <6.0RxJS ^6.5.3 || ^7.4.0zone.js ~0.15.0
-
→ 21Angular 21.2.25
ng update @angular/core@21 @angular/cli@21Node.js ^20.19.0 || ^22.12.0 || >=24.0.0TypeScript >=5.9 <6.1RxJS ^6.5.3 || ^7.4.0zone.js ~0.15.0 || ~0.16.0
- Move unit tests from Karma to Vitest
Vitest is the Angular CLI default from 21 (@angular/build:unit-test). Jasmine-specific calls (spyOn, jasmine.*) need rewriting.
- Prepare for zoneless: move components to OnPush, then drop zone.js 18
Upgraded apps keep zone.js through provideZoneChangeDetection() until it is removed.
- Move unit tests from Karma to Vitest
-
→ 22Angular 22.2.3
ng update @angular/core@22 @angular/cli@22Node.js ^22.22.3 || ^24.15.0 || >=26.0.0TypeScript >=6.0 <6.1RxJS ^6.5.3 || ^7.4.0zone.js ~0.15.0 || ~0.16.0
Angular version & tooling
PoorAngular 12.2.17, 10 majors behind 22.
- Installed
- 12.2.17
- package-lock.json
- Latest
- 22
- npm registry
- Majors behind
- 10
- Build system
- webpack
-
HighAngular 12 is 10 majors behind 22 and out of support
Angular supports each major for 18 months, so only the newest three get fixes; 12 receives no security patches.
ng updatemoves one major at a time, which makes this 10 sequential upgrade steps, each with its own migrations to review. -
Medium1 project still built with the webpack builder
The esbuild-based
applicationbuilder has been the default since Angular 17 and builds several times faster.ng update @angular/cli --name use-application-buildermigrates the configuration. Projects: ang2-conduit. -
Medium
protractoris end of lifeEnd of life since 2023. Replaced by Playwright or Cypress.
-
Medium
tslintis end of lifeDeprecated since 2019. Replaced by ESLint with
angular-eslint. -
Medium
codelyzeris end of lifeA set of TSLint rules, so it died with TSLint. Replaced by
angular-eslint.
Deprecated APIs
GoodNothing deprecated as of Angular 12 is in use; APIs deprecated in later versions surface at each upgrade step.
- Deprecated symbols
- 0
- Files affected
- 0
- Legacy template directives
- 13
- not deprecated in this version
Third-party compatibility
GoodNo third-party package depends on Angular.
- Depend on Angular
- 0
- third-party packages
- Block the upgrade
- 0
- to Angular 22
- Peer mismatches
- 0
- with Angular 12
- Deprecated on npm
- 0
Change detection & zoneless readiness
PoorRuns on zone.js; 0% of 18 components use OnPush.
- Mode
- zone.js
- OnPush
- 0%
- 0 of 18 components
- Files injecting NgZone
- 0
- Zone test helpers
- 0
-
NoteZoneless change detection needs Angular 20.2 or newer
Upgrade first; OnPush coverage is the preparation that pays off now.
-
Medium18 components use eager change detection (100%)
Without
changeDetection: ChangeDetectionStrategy.OnPusha component is checked on every change detection cycle and usually relies on zone.js to notice mutations. These are the components to review before going zoneless.- src/app/app.component.ts:5
- src/app/article/article-comment.component.ts:6
- src/app/article/article.component.ts:14
- src/app/auth/auth.component.ts:7
- src/app/editor/editor.component.ts:7
- and 13 more
Components & templates
Poor18 components: 0% standalone, 0% signal inputs, 0% built-in control flow.
- Components
- 18
- Standalone
- 0%
- 16 NgModules
- Signal inputs
- 0%
- 0 of 9
- Signal outputs
- 0%
- 0 of 3
- Built-in control flow
- 0%
- 0 of 13 blocks
- @defer blocks
- 0
-
Medium18 components still declared in NgModules (16 NgModules in total)
Standalone components are the default since Angular 19 and what every new API assumes.
ng generate @angular/core:standaloneconverts declarations, removes the emptied NgModules and switches bootstrapping, in three passes that can be reviewed one at a time.- src/app/app.component.ts:5
- src/app/article/article-comment.component.ts:6
- src/app/article/article.component.ts:14
- src/app/auth/auth.component.ts:7
- src/app/editor/editor.component.ts:7
- and 13 more
-
Medium9
@Input()decorators and 3@Output()decorators leftSignal inputs (
input()) make inputs readable incomputed()and effects withoutngOnChanges, and are what zoneless change detection tracks.ng generate @angular/core:signal-input-migrationandng generate @angular/core:output-migrationconvert most of them; the rest are usually inputs written to from inside the component. -
Low13 uses of
*ngIf,*ngForand[ngSwitch]Built-in control flow (
@if,@for,@switch) is available from Angular 17.ng generate @angular/core:control-flowmigrates most templates automatically.
State management
FairNo classic NgRx, 0 signal()/computed() calls, 0 signal-store files.
- Classic NgRx files
- 0
- Signal store files
- 0
- signal() / computed()
- 0
- 0 toSignal()
- BehaviorSubject services
- 1
-
Low1 service holds state in a
BehaviorSubjectEach is a candidate for a
signal()-based service: templates read it without the async pipe,computed()replacescombineLatestchains, and zoneless change detection tracks it automatically.toObservable()keeps existing RxJS consumers working during the move.- src/app/core/services/user.service.ts:12
Architecture
Good79% of 14 routes lazy, 0 files over 500 lines, 28 classes with constructor injection.
- Lazy routes
- 79%
- 11 of 14
- Large files
- 0
- over 500 lines
- Constructor injection
- 28
- classes; 0 inject() calls
- Class guards
- 7
- and interceptors
- Hotspots
- -
- shallow clone: no history (fetch-depth: 0)
-
Low7 class-based guards and interceptors
Resolve, CanActivate, HttpInterceptor. Functional guards (
CanActivateFn,ResolveFn) and interceptors (HttpInterceptorFnwithwithInterceptors) are the current style: a function withinject()inside, no class, no provider. Class interceptors also needwithInterceptorsFromDi()to keep working withprovideHttpClient.- src/app/article/article-resolver.service.ts:8
- src/app/auth/no-auth-guard.service.ts:8
- src/app/core/interceptors/http.token.interceptor.ts:7
- src/app/core/services/auth-guard.service.ts:8
- src/app/editor/editable-article-resolver.service.ts:8
- and 2 more
-
Low28 classes inject through the constructor
inject()is the current default (0 calls already in the code). It works in field initialisers and functions, and it is what signal-based code expects.ng generate @angular/core:injectmigrates constructors automatically.- src/app/app.component.ts:10
- src/app/article/article-comment.component.ts:11
- src/app/article/article-resolver.service.ts:10
- src/app/article/article.component.ts:28
- src/app/auth/auth.component.ts:18
- and 23 more
Testing
PoorKarma, 0 spec files, 0% of components and services with a spec.
- Unit-test runner
- Karma
- Spec files
- 0
- With a spec
- 0%
- 0 of 32 component/service files
- End-to-end
- Protractor
-
HighUnit tests run on Karma, which is deprecated
Karma was deprecated in 2023 and receives no further development. Vitest is the Angular CLI's default runner since v21 (
@angular/build:unit-test). With no specs written yet, moving costs only the configuration, and the first specs can be written for Vitest directly. -
HighNo unit tests found
32 component and service files without a single spec. Every refactoring and upgrade step is verified by hand.
-
HighEnd-to-end tests use Protractor, which is end of life
Protractor reached end of life in 2023 and gets no fixes, including for new browser versions. Playwright and Cypress are the usual replacements.
Type safety
PoorstrictNullChecks off, strictTemplates off, 13 explicit any.
- strictNullChecks
- off
- default in TypeScript 4
- strictTemplates
- off
- default in Angular 12
- noImplicitAny
- off
- default in TypeScript 4
- Explicit any
- 13
- 8.2 per 1 000 lines
- Non-null assertions
- 0
-
High
strictNullChecksis offEvery value that may be
nullorundefinedis typed as if it never is, so the most common runtime error in an Angular app is invisible to the compiler. In a large codebase switching it on is staged: a separate tsconfig that checks one folder at a time, with a count that may only go down. -
High
strictTemplatesis offTemplate bindings are only loosely type-checked: a wrong input type, a misspelled output payload or a possibly-undefined value passed to a component compiles and fails at runtime. Turning it on typically surfaces a batch of real bugs alongside the type noise.
-
Medium
noImplicitAnyis offAn unannotated parameter silently becomes
any, and no lint rule that counts the wordanycan see it. -
Medium13 explicit
anyin application code (8.2 per 1 000 lines)Files with the most are listed first. Each
anyswitches type checking off for everything that flows through it.- src/app/core/services/api.service.ts:14
- src/app/core/interceptors/http.token.interceptor.ts:11
- src/test.ts:16
- src/app/article/article-resolver.service.ts:18
- src/app/editor/editable-article-resolver.service.ts:19
- and 2 more
-
Low1
@ts-ignore/@ts-expect-errorcommentEach switches off checking for the next line, including errors nobody has seen yet.
Security
PoorNo sanitizer bypasses, direct DOM HTML writes or eval in 69 files; 1 sanitized [innerHTML] binding; 23 known vulnerabilities in dependencies.
- Direct DOM HTML writes
- 0
- innerHTML =, insertAdjacentHTML
- Sanitizer bypasses
- 0
- bypassSecurityTrust*
- eval / new Function
- 0
- [innerHTML] bindings
- 1
- sanitized by Angular
- Known vulnerabilities
- 23
- in 35 direct dependencies checked
-
High23 known vulnerabilities in 4 dependencies (15 high or critical)
@angular/common12.2.17: 8 advisories (CVE-2026-54266, CVE-2026-54268, CVE-2025-66035, …), all fixed by 20.3.34;@angular/compiler12.2.17: 6 advisories (CVE-2026-54265, CVE-2026-50557, CVE-2026-88057, …), all fixed by 20.3.28;@angular/core12.2.17: 7 advisories (CVE-2026-52725, CVE-2026-50557, CVE-2026-88057, …), all fixed by 20.3.28;@angular/router12.2.17: 2 advisories (CVE-2026-111752, CVE-2026-101896), all fixed by 20.3.33. Direct dependencies at their exact versions, from the advisories in osv.dev; the full dependency tree isnpm audit's job. -
Low1
[innerHTML]binding in 1 templateAngular sanitizes these, so they are safe on their own: scripts and event handlers are stripped. They become a hole only when the bound value went through
bypassSecurityTrustHtml, which is worth checking for each one.- src/app/article/article.component.html
Circular dependencies
GoodNo import cycles between application files.
- Tangles
- 0
- groups of files in a loop
- Files involved
- 0
- Largest tangle
- 0
- files
Bundle size
InfoNo build stats found, so the bundle size is not part of this report.
-
NoteRun
ng build --stats-json(ornx build <app> --stats-json) and re-run to include the bundle size