ngx-performance-diagnostics
December 10, 2025 Β· View on GitHub
π Real-time performance monitoring and diagnostics for Angular applications
Detect performance issues, excessive change detection cycles, and memory leaks in your Angular applications with zero configuration. Perfect for development and debugging!
β¨ Features
- π Change Detection Monitor - Detect components with excessive CD cycles
- πΎ Memory Leak Detector - Track memory usage and identify leaks
- π Visual Panels - Real-time diagnostics UI panels
- π― Zero Config - Works out of the box, no setup required
- π Lightweight - Minimal overhead, dev-only friendly
- π¦ Standalone - Fully compatible with Angular standalone components
- π§ Flexible - Use individual tools or full diagnostic suite
π¦ Installation
npm install ngx-performance-diagnostics --save-dev
π Quick Start
1. Add Diagnostic Panels to Your Layout
import { Component } from '@angular/core';
import {
CdMonitorPanelComponent,
MemoryLeakPanelComponent
} from 'ngx-performance-diagnostics';
@Component({
selector: 'app-root',
standalone: true,
imports: [
// ... your imports
CdMonitorPanelComponent, // CD Monitor (right panel)
MemoryLeakPanelComponent, // Memory Monitor (left panel)
],
template: `
<router-outlet></router-outlet>
<!-- Diagnostic panels (development only) -->
@if (!isProduction) {
<ngx-cd-monitor-panel></ngx-cd-monitor-panel>
<ngx-memory-leak-panel></ngx-memory-leak-panel>
}
`
})
export class AppComponent {
isProduction = false; // Set from environment
}
2. Monitor a Component
import { Component } from '@angular/core';
import { ChangeDetectionMonitorDirective } from 'ngx-performance-diagnostics';
@Component({
selector: 'app-my-component',
standalone: true,
imports: [ChangeDetectionMonitorDirective],
template: `
<div cdMonitor="MyComponent">
<!-- Your component content -->
<h1>{{ title }}</h1>
</div>
`
})
export class MyComponent {
title = 'Hello World';
}
3. Run Chrome with Memory Profiling Flags
# macOS
open -a "Google Chrome" --args --enable-precise-memory-info --expose-gc
# Windows
chrome.exe --enable-precise-memory-info --expose-gc
# Linux
google-chrome --enable-precise-memory-info --expose-gc
4. Start Debugging!
- Open your Angular app
- Click "Start" in the Memory Panel (bottom-left)
- Leave the app idle for 1-2 minutes
- Check the panels for issues:
- CD Monitor (bottom-right): Shows change detection statistics
- Memory Monitor (bottom-left): Shows memory trends
π API Documentation
Change Detection Monitor Directive
Monitor change detection cycles for any component:
<div cdMonitor="ComponentName" [cdMonitorThreshold]="50">
<!-- Component content -->
</div>
Inputs:
cdMonitor: string- Component name for identificationcdMonitorThreshold: number- Warning threshold in cycles/second (default: 100)
What it tracks:
- Cycles per second (c/s)
- Total checks
- Average time between checks
- Min/Max time between checks
Change Detection Monitor Service
Programmatic access to CD statistics:
import { ChangeDetectionMonitorService } from 'ngx-performance-diagnostics';
export class MyComponent implements OnInit {
constructor(private cdMonitor: ChangeDetectionMonitorService) {}
ngOnInit() {
// Subscribe to statistics
this.cdMonitor.stats$.subscribe(summary => {
console.log('Active:', summary.activeComponents);
console.log('Problematic:', summary.problematicComponents);
});
// Get current stats
const stats = this.cdMonitor.getStats();
// Export to JSON
const json = this.cdMonitor.exportStats();
// Clear all stats
this.cdMonitor.clearStats();
}
}
Memory Leak Detector Service
Monitor memory usage and detect leaks:
import { MemoryLeakDetectorService } from 'ngx-performance-diagnostics';
export class MyComponent implements OnInit, OnDestroy {
constructor(private memoryMonitor: MemoryLeakDetectorService) {}
ngOnInit() {
// Start monitoring
this.memoryMonitor.startMonitoring();
// Get report
const report = this.memoryMonitor.getReport();
console.log('Is leaking:', report.isLeaking);
console.log('Trend:', report.trendPercentPerMinute, '% per minute');
// Export report
const json = this.memoryMonitor.exportReport();
// Force garbage collection (requires --expose-gc flag)
this.memoryMonitor.forceGC();
}
ngOnDestroy() {
this.memoryMonitor.stopMonitoring();
}
}
CD Monitor Panel Component
Visual panel showing change detection statistics:
<ngx-cd-monitor-panel></ngx-cd-monitor-panel>
Features:
- Real-time component statistics
- Click component to highlight in DOM
- Export reports to JSON
- Clear statistics
Memory Leak Panel Component
Visual panel showing memory usage:
<ngx-memory-leak-panel></ngx-memory-leak-panel>
Features:
- Live memory chart
- Trend analysis
- Start/stop monitoring
- Force garbage collection
- Export reports to JSON
π Interpreting Results
Change Detection Monitor
| c/s (cycles/sec) | Status | Action |
|---|---|---|
| < 10 | β Excellent | No action needed |
| 10-50 | β οΈ Acceptable | Monitor |
| 50-100 | πΆ Concerning | Investigate |
| > 100 | π¨ Critical | Fix immediately |
Common issues:
- Getters in templates
- Functions called in templates
- Missing
OnPushchange detection strategy - Unsubscribed observables triggering updates
Memory Leak Detector
| Trend %/min | Status | Action |
|---|---|---|
| < 0 | β Decreasing (GC working) | OK |
| 0-2 | β Stable | OK |
| 2-5 | β οΈ Suspicious growth | Investigate |
| > 5 | π¨ Leak detected | Fix immediately |
Common issues:
- Unsubscribed RxJS observables
- Event listeners not removed
- Intervals/timeouts not cleared
- Circular references
- Large objects in closures
π§ Common Fixes
Fix 1: Unsubscribed RxJS Observables
// β BAD
ngOnInit() {
this.service.data$.subscribe(data => this.data = data);
}
// β
GOOD - Option 1: takeUntil
private destroy$ = new Subject<void>();
ngOnInit() {
this.service.data$
.pipe(takeUntil(this.destroy$))
.subscribe(data => this.data = data);
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
// β
GOOD - Option 2: async pipe (preferred)
@Component({
template: `<div>{{ data$ | async }}</div>`
})
export class MyComponent {
data$ = this.service.data$;
}
Fix 2: Getters in Templates
// β BAD - getter called on every CD cycle
get total(): number {
return this.items.reduce((sum, item) => sum + item.price, 0);
}
// β
GOOD - computed once
total = 0;
ngOnChanges() {
this.total = this.items.reduce((sum, item) => sum + item.price, 0);
}
Fix 3: OnPush Change Detection
// β BAD - Default strategy checks on every event
@Component({
changeDetection: ChangeDetectionStrategy.Default
})
// β
GOOD - OnPush only checks on input changes
@Component({
changeDetection: ChangeDetectionStrategy.OnPush
})
Fix 4: Event Listeners
// β BAD
ngOnInit() {
window.addEventListener('resize', this.onResize);
}
// β
GOOD
ngOnInit() {
window.addEventListener('resize', this.onResize);
}
ngOnDestroy() {
window.removeEventListener('resize', this.onResize);
}
π― Usage Patterns
Development Only
import { isDevMode } from '@angular/core';
@Component({
template: `
@if (isDevMode()) {
<ngx-cd-monitor-panel></ngx-cd-monitor-panel>
<ngx-memory-leak-panel></ngx-memory-leak-panel>
}
`
})
Conditional Monitoring
// Monitor only specific components
@Component({
template: `
<div [cdMonitor]="shouldMonitor ? 'MyComponent' : null">
<!-- Content -->
</div>
`
})
export class MyComponent {
shouldMonitor = !environment.production;
}
Custom Thresholds
// Lower threshold for critical components
<div cdMonitor="CriticalComponent" [cdMonitorThreshold]="30">
<!-- Lower threshold = earlier warnings -->
</div>
π¬ Advanced Usage
Programmatic Monitoring
import {
ChangeDetectionMonitorService,
MemoryLeakDetectorService
} from 'ngx-performance-diagnostics';
@Component({/*...*/})
export class DiagnosticsComponent implements OnInit {
constructor(
private cdMonitor: ChangeDetectionMonitorService,
private memoryMonitor: MemoryLeakDetectorService
) {}
ngOnInit() {
// Start memory monitoring
this.memoryMonitor.startMonitoring();
// Check every 10 seconds
setInterval(() => {
const cdReport = this.cdMonitor.exportStats();
const memReport = this.memoryMonitor.exportReport();
// Send to analytics, log to console, etc.
this.sendToAnalytics({ cd: cdReport, memory: memReport });
}, 10000);
}
sendToAnalytics(data: any) {
// Your analytics implementation
}
}
Custom Export
exportDiagnostics() {
const report = {
timestamp: new Date().toISOString(),
changeDetection: JSON.parse(this.cdMonitor.exportStats()),
memory: JSON.parse(this.memoryMonitor.exportReport()),
userAgent: navigator.userAgent,
url: window.location.href
};
// Download or send to server
this.downloadReport(report);
}
π οΈ Configuration
TypeScript Configuration
No special configuration needed! The library is built with strict mode and full type safety.
Angular Configuration
Works with:
- β Angular 17+
- β Angular 18+
- β Angular 19+
- β Standalone components
- β NgModules
- β Ivy compiler
π€ Contributing
Contributions are welcome! Please read our Contributing Guide for details.
Development Setup
# Clone repository
git clone https://github.com/maciekv/ngx-performance-diagnostics.git
cd ngx-performance-diagnostics
# Install dependencies
npm install
# Build library
npm run build
# Run tests
npm test
π License
MIT Β© [Maciej Osytek]
π Acknowledgments
Built for the Angular community with β€οΈ
π Support
- π Report Issues
- π¬ Discussions
- π Documentation
πΊοΈ Roadmap
- Unit tests
- E2E tests
- Zone.js integration
- Performance timeline integration
- Custom reporters
- CI/CD performance checks
Happy Debugging! ππ