askill
angular-perf

angular-perfSafety 100Repository

Angular performance and optimization patterns

0 stars
1.2k downloads
Updated 2/20/2026

Package Files

Loading files...
SKILL.md

Minko Gechev: Angular Performance

Minko Gechev's core belief: Performance is a feature, not an afterthought. Every millisecond of load time and every kilobyte of bundle size affects user experience.

The Foundational Principle

"The fastest code is code that doesn't run. The smallest bundle is the one you don't ship."

Performance optimization in Angular is about:

  • Shipping less JavaScript
  • Running less change detection
  • Loading only what's needed
  • Measuring before optimizing

Core Principles

1. Lazy Loading Is Non-Negotiable

Every feature module should be lazy loaded unless proven otherwise.

Not this:

// app.module.ts - everything loaded upfront
@NgModule({
  imports: [
    UsersModule,
    AdminModule,
    ReportsModule,
    SettingsModule  // User may never visit settings
  ]
})
class AppModule {}

This:

// app-routing.module.ts - load on demand
const routes: Routes = [
  { path: 'users', loadChildren: () => import('./users/users.module').then(m => m.UsersModule) },
  { path: 'admin', loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule) },
  { path: 'reports', loadChildren: () => import('./reports/reports.module').then(m => m.ReportsModule) },
  { path: 'settings', loadChildren: () => import('./settings/settings.module').then(m => m.SettingsModule) }
];

With standalone components (Angular 14+):

const routes: Routes = [
  {
    path: 'dashboard',
    loadComponent: () => import('./dashboard.component').then(c => c.DashboardComponent)
  }
];

2. OnPush Change Detection Strategy

Default change detection checks every component on every event. OnPush checks only when inputs change.

Not this:

@Component({
  // Default change detection - checks on every click anywhere
})
class ExpensiveListComponent {
  @Input() items: Item[];
}

This:

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush  // Only checks when items reference changes
})
class ExpensiveListComponent {
  @Input() items: Item[];
}

Rules for OnPush:

  • All @Input() must be immutable (new reference on change)
  • Use async pipe for observables (triggers change detection correctly)
  • Call ChangeDetectorRef.markForCheck() only when truly needed

3. TrackBy for All ngFor

Without trackBy, Angular destroys and recreates DOM for every change.

Not this:

<li *ngFor="let user of users">{{ user.name }}</li>
<!-- Entire list re-rendered when any user changes -->

This:

<li *ngFor="let user of users; trackBy: trackByUserId">{{ user.name }}</li>
<!-- Only changed items re-rendered -->
trackByUserId(index: number, user: User): string {
  return user.id;
}

4. Async Pipe Over Manual Subscriptions

Manual subscriptions leak memory. Async pipe handles cleanup.

Not this:

class UserComponent implements OnInit, OnDestroy {
  user: User;
  private subscription: Subscription;

  ngOnInit() {
    this.subscription = this.userService.getUser().subscribe(u => this.user = u);
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();  // Easy to forget
  }
}

This:

class UserComponent {
  user$ = this.userService.getUser();

  constructor(private userService: UserService) {}
}
<div *ngIf="user$ | async as user">{{ user.name }}</div>

5. Bundle Analysis and Budgets

Set budgets, enforce them, analyze violations.

angular.json:

{
  "budgets": [
    {
      "type": "initial",
      "maximumWarning": "500kb",
      "maximumError": "1mb"
    },
    {
      "type": "anyComponentStyle",
      "maximumWarning": "2kb",
      "maximumError": "4kb"
    }
  ]
}

Analyze bundles:

ng build --stats-json
npx webpack-bundle-analyzer dist/stats.json

6. Preloading Strategies

Don't just lazy load—preload intelligently.

// Preload all modules after initial load
@NgModule({
  imports: [RouterModule.forRoot(routes, {
    preloadingStrategy: PreloadAllModules
  })]
})

// Or custom strategy - preload based on user behavior
@Injectable()
class CustomPreloadingStrategy implements PreloadingStrategy {
  preload(route: Route, load: () => Observable<any>): Observable<any> {
    return route.data?.['preload'] ? load() : of(null);
  }
}

7. Virtual Scrolling for Large Lists

Never render thousands of DOM nodes. Use virtual scrolling.

import { ScrollingModule } from '@angular/cdk/scrolling';

@Component({
  template: `
    <cdk-virtual-scroll-viewport itemSize="50" class="viewport">
      <div *cdkVirtualFor="let item of items" class="item">
        {{ item.name }}
      </div>
    </cdk-virtual-scroll-viewport>
  `
})
class LargeListComponent {
  items = Array.from({ length: 10000 }, (_, i) => ({ name: `Item ${i}` }));
}

8. Web Workers for Heavy Computation

Offload CPU-intensive work to avoid blocking the main thread.

// app.worker.ts
addEventListener('message', ({ data }) => {
  const result = heavyComputation(data);
  postMessage(result);
});

// component.ts
if (typeof Worker !== 'undefined') {
  const worker = new Worker(new URL('./app.worker', import.meta.url));
  worker.onmessage = ({ data }) => {
    this.result = data;
  };
  worker.postMessage(this.inputData);
}

9. Image Optimization with NgOptimizedImage

Angular's built-in image optimization directive.

import { NgOptimizedImage } from '@angular/common';

@Component({
  imports: [NgOptimizedImage],
  template: `
    <img ngSrc="hero.jpg" width="800" height="600" priority>
    <img ngSrc="thumbnail.jpg" width="200" height="150" loading="lazy">
  `
})

Benefits:

  • Automatic lazy loading
  • Prevents layout shift (requires width/height)
  • Preconnect hints for CDNs
  • Warning for LCP images without priority

10. Defer Blocks (Angular 17+)

Declarative lazy loading in templates.

@defer (on viewport) {
  <heavy-component />
} @placeholder {
  <lightweight-skeleton />
} @loading (minimum 500ms) {
  <spinner />
}

Trigger options:

  • on viewport - when enters viewport
  • on idle - when browser is idle
  • on interaction - on click/focus
  • on hover - on mouse hover
  • on timer(500ms) - after delay

The Gechev Test

Before shipping, ask:

  1. Is everything lazy loaded? Feature modules, standalone components?
  2. Is OnPush used everywhere possible? With immutable inputs?
  3. Do all ngFor have trackBy? No exceptions?
  4. Am I within bundle budgets? Have I analyzed what's in the bundle?
  5. Are large lists virtualized? Or paginated?
  6. Is heavy computation off main thread? Web workers for CPU work?
  7. Are images optimized? Using NgOptimizedImage?

When Reviewing Code

Apply these checks:

  • Lazy loading for all feature modules
  • ChangeDetectionStrategy.OnPush on components
  • trackBy on all *ngFor
  • async pipe instead of manual subscriptions
  • Bundle budgets configured and passing
  • Virtual scrolling for lists > 100 items
  • Images use NgOptimizedImage
  • No synchronous heavy computation in components
  • Preloading strategy configured

Performance Debugging

// Enable Angular DevTools profiler
// In browser: Angular DevTools extension

// Measure change detection
import { enableDebugTools } from '@angular/platform-browser';
enableDebugTools(appRef.components[0]);
// Then in console: ng.profiler.timeChangeDetection()

// Trace what triggers change detection
constructor(private ngZone: NgZone) {
  ngZone.onStable.subscribe(() => console.log('CD cycle complete'));
}

When NOT to Use This Skill

Use a different skill when:

  • Designing component architecture → Use angular-core (DI, testability)
  • Applying design patterns → Use design-patterns
  • General code clarity → Use clarity
  • Type system design → Use typescript (TypeScript)

Minko Gechev is the Angular performance skill—use it for optimization, lazy loading, and runtime efficiency.

Sources

  • Gechev, "Angular Performance Checklist" (GitHub)
  • Angular documentation - Performance section
  • web.dev Core Web Vitals guidance
  • Gechev's conference talks on Angular performance

"Measure first. Optimize what matters. Ship less JavaScript." — Minko Gechev

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

88/100Analyzed 2/23/2026

Comprehensive Angular performance skill with excellent code examples showing patterns vs anti-patterns. Well-organized with 10 major optimization techniques, clear checklists, and debugging guidance. The "Not this" vs "This" format is highly actionable. Minor tag mismatch (ci-cd/github/testing don't align with performance focus). Good reference-style content applicable across Angular projects.

100
90
85
85
90

Metadata

Licenseunknown
Version-
Updated2/20/2026
PublisherObjective-Arts

Tags

ci-cdgithubtesting