@code-zetta/ng-profiler
Version:
A tiny in-app profiler overlay for Angular that works in both zoned and zoneless applications
351 lines (341 loc) • 10.9 kB
TypeScript
import * as i0 from '@angular/core';
import { InjectionToken, ApplicationRef, OnInit, OnDestroy, ElementRef, NgZone, ModuleWithProviders, Provider } from '@angular/core';
import * as i1 from '@angular/common';
import { Observable } from 'rxjs';
interface NgProfilerConfig {
/** Enable profiler in production (default: false) */
enableInProduction?: boolean;
/** Hotkey to toggle overlay (default: 'Ctrl+Shift+P') */
hotkey?: string;
/** Position of overlay (default: 'top-right') */
position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
/** Threshold for render count warnings (default: 10) */
renderCountThreshold?: number;
/** Threshold for frame duration warnings in ms (default: 16.67) */
frameDurationThreshold?: number;
/** Enable heatmap outlines (default: true) */
enableHeatmap?: boolean;
/** Enable performance measurement (default: true) */
enableMeasurement?: boolean;
}
declare const NG_PROFILER_CONFIG: InjectionToken<NgProfilerConfig>;
interface ProfilerStats {
/** Last tick/frame duration in ms */
lastFrameDuration: number;
/** Average frame duration in ms */
averageFrameDuration: number;
/** Total number of frames measured */
frameCount: number;
/** Top components by render count */
topComponents: ComponentRenderStats[];
/** Timestamp of last measurement */
lastMeasurement: number;
/** Performance recommendations */
recommendations?: PerformanceRecommendation[];
}
interface ComponentRenderStats {
/** Component name or element tag */
name: string;
/** Number of renders */
renderCount: number;
/** Severity level */
severity: 'low' | 'medium' | 'high';
/** Element reference for heatmap */
element?: HTMLElement;
}
interface FrameMeasurement {
duration: number;
timestamp: number;
}
interface PerformanceRecommendation {
id: string;
type: 'warning' | 'error' | 'info' | 'optimization';
title: string;
description: string;
severity: 'low' | 'medium' | 'high' | 'critical';
category: 'performance' | 'memory' | 'rendering' | 'best-practice';
suggestions: string[];
impact: string;
priority: number;
}
declare global {
interface Window {
Zone?: any;
}
}
declare class RecommendationService {
/**
* Analyze performance data and generate recommendations
*/
analyzePerformance(stats: ProfilerStats): PerformanceRecommendation[];
/**
* Analyze frame performance issues
*/
private analyzeFramePerformance;
/**
* Analyze component render issues
*/
private analyzeComponentRenders;
/**
* Analyze component patterns and architecture
*/
private analyzeComponentPatterns;
/**
* Analyze template optimization opportunities
*/
private analyzeTemplateOptimization;
/**
* Analyze memory usage patterns
*/
private analyzeMemoryUsage;
/**
* Analyze best practices and advanced optimizations
*/
private analyzeBestPractices;
/**
* Analyze network performance patterns
*/
private analyzeNetworkPerformance;
/**
* Analyze bundle optimization opportunities
*/
private analyzeBundleOptimization;
/**
* Analyze state management patterns
*/
private analyzeStateManagement;
/**
* Get recommendation by ID
*/
getRecommendationById(id: string, stats: ProfilerStats): PerformanceRecommendation | null;
/**
* Get recommendations by category
*/
getRecommendationsByCategory(category: string, stats: ProfilerStats): PerformanceRecommendation[];
/**
* Get critical recommendations only
*/
getCriticalRecommendations(stats: ProfilerStats): PerformanceRecommendation[];
/**
* Check if performance is within acceptable thresholds
*/
isPerformanceAcceptable(stats: ProfilerStats): boolean;
/**
* Get performance score (0-100)
*/
getPerformanceScore(stats: ProfilerStats): number;
/**
* Get performance health status
*/
getPerformanceHealth(stats: ProfilerStats): 'excellent' | 'good' | 'fair' | 'poor' | 'critical';
/**
* Get performance summary
*/
getPerformanceSummary(stats: ProfilerStats): {
score: number;
health: string;
acceptable: boolean;
criticalIssues: number;
warnings: number;
};
static ɵfac: i0.ɵɵFactoryDeclaration<RecommendationService, never>;
static ɵprov: i0.ɵɵInjectableDeclaration<RecommendationService>;
}
declare class ProfilerStore {
private recommendationService;
private renderCounts;
private elementMap;
private frameMeasurements;
private maxFrameHistory;
private isPaused;
constructor(recommendationService: RecommendationService);
private statsSubject;
stats$: Observable<ProfilerStats>;
/**
* Increment render count for a component
*/
incrementRenderCount(name: string, element?: HTMLElement): void;
/**
* Add frame measurement
*/
addFrameMeasurement(duration: number): void;
/**
* Get severity level based on render count
*/
private getSeverity;
/**
* Update statistics
*/
private updateStats;
/**
* Reset all statistics
*/
reset(): void;
/**
* Export current statistics as JSON
*/
exportStats(): string;
/**
* Get current render count for a component
*/
getRenderCount(name: string): number;
/**
* Get all render counts
*/
getAllRenderCounts(): Map<string, number>;
/**
* Pause render counting
*/
pauseRenderCounting(): void;
/**
* Resume render counting
*/
resumeRenderCounting(): void;
static ɵfac: i0.ɵɵFactoryDeclaration<ProfilerStore, never>;
static ɵprov: i0.ɵɵInjectableDeclaration<ProfilerStore>;
}
declare class NgProfilerService {
private appRef;
private profilerStore;
private config;
private isEnabled;
private isZoned;
private originalTick;
private frameStartTime;
private longTaskObserver;
private animationFrameId;
constructor(appRef: ApplicationRef, profilerStore: ProfilerStore, config: NgProfilerConfig);
/**
* Initialize the profiler
*/
initialize(): void;
/**
* Check if profiler should be enabled
*/
private shouldEnable;
/**
* Check if running in production
*/
private isProduction;
/**
* Detect if Zone.js is present
*/
private detectZone;
/**
* Patch ApplicationRef.tick() for zoned applications
*/
private patchApplicationRef;
/**
* Setup measurement for zoneless applications
*/
private setupZonelessMeasurement;
/**
* Setup hotkey listener
*/
private setupHotkey;
/**
* Toggle overlay visibility
*/
toggleOverlay(): void;
/**
* Cleanup resources
*/
destroy(): void;
/**
* Get current configuration
*/
getConfig(): NgProfilerConfig;
/**
* Check if profiler is enabled
*/
isProfilerEnabled(): boolean;
/**
* Check if running in zoned mode
*/
isZonedMode(): boolean;
/**
* Pause profiling temporarily
*/
pauseProfiling(): void;
/**
* Resume profiling
*/
resumeProfiling(): void;
static ɵfac: i0.ɵɵFactoryDeclaration<NgProfilerService, never>;
static ɵprov: i0.ɵɵInjectableDeclaration<NgProfilerService>;
}
declare class NgProfilerOverlayComponent implements OnInit, OnDestroy {
private profilerStore;
profilerService: NgProfilerService;
isVisible: boolean;
stats: ProfilerStats;
private subscription;
position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
constructor(profilerStore: ProfilerStore, profilerService: NgProfilerService);
ngOnInit(): void;
ngOnDestroy(): void;
onEscapeKey(): void;
toggleVisibility(): void;
resetStats(): void;
exportStats(): void;
exportPDF(): Promise<void>;
trackByComponent(index: number, component: ComponentRenderStats): string;
trackByRecommendation(index: number, recommendation: PerformanceRecommendation): string;
showAllRecommendations(): void;
static ɵfac: i0.ɵɵFactoryDeclaration<NgProfilerOverlayComponent, never>;
static ɵcmp: i0.ɵɵComponentDeclaration<NgProfilerOverlayComponent, "codezetta-ng-profiler-overlay", never, {}, {}, never, never, true, never>;
}
declare class NgProfilerDirective implements OnInit, OnDestroy {
private elementRef;
private profilerStore;
private ngZone;
componentName?: string;
private renderCount;
private elementName;
private isDestroyed;
private observer;
private resizeObserver;
constructor(elementRef: ElementRef<HTMLElement>, profilerStore: ProfilerStore, ngZone: NgZone);
ngOnInit(): void;
ngOnDestroy(): void;
/**
* Setup passive observation using MutationObserver and ResizeObserver
*/
private setupPassiveObservation;
/**
* Cleanup observers to prevent memory leaks
*/
private cleanupObservers;
/**
* Get component name for tracking
*/
private getComponentName;
/**
* Update heatmap attribute based on render count
*/
private updateHeatmapAttribute;
/**
* Get severity level based on render count
*/
private getSeverityLevel;
/**
* Get current render count
*/
getRenderCount(): number;
static ɵfac: i0.ɵɵFactoryDeclaration<NgProfilerDirective, never>;
static ɵdir: i0.ɵɵDirectiveDeclaration<NgProfilerDirective, "[codezettaNgProfiler]", never, { "componentName": { "alias": "codezettaNgProfiler"; "required": false; }; }, {}, never, never, true, never>;
}
declare class NgProfilerModule {
static forRoot(config?: NgProfilerConfig): ModuleWithProviders<NgProfilerModule>;
static ɵfac: i0.ɵɵFactoryDeclaration<NgProfilerModule, never>;
static ɵmod: i0.ɵɵNgModuleDeclaration<NgProfilerModule, never, [typeof i1.CommonModule, typeof NgProfilerOverlayComponent, typeof NgProfilerDirective], [typeof NgProfilerOverlayComponent, typeof NgProfilerDirective]>;
static ɵinj: i0.ɵɵInjectorDeclaration<NgProfilerModule>;
}
/**
* Provides the NgProfiler services for standalone components
* @param config Optional configuration for the profiler
* @returns Array of providers for dependency injection
*/
declare function provideNgProfiler(config?: NgProfilerConfig): Provider[];
export { NG_PROFILER_CONFIG, NgProfilerDirective, NgProfilerModule, NgProfilerOverlayComponent, NgProfilerService, ProfilerStore, RecommendationService, provideNgProfiler };
export type { ComponentRenderStats, FrameMeasurement, NgProfilerConfig, PerformanceRecommendation, ProfilerStats };