Performance API wrapper with Core Web Vitals support.
import { PerformanceMonitor } from '@zappzarapp/browser-utils/performance';
// Create an instance
const monitor = PerformanceMonitor.create();
// Create marks and measures
monitor.mark('start');
await doWork();
monitor.mark('end');
const measure = monitor.measure('work', 'start', 'end');
console.log(`Work took ${measure?.duration}ms`);
// Get Core Web Vitals (including INP)
const metrics = monitor.getMetrics();
console.log('TTFB:', metrics.ttfb, 'FCP:', metrics.fcp, 'INP:', metrics.inp);| Feature | Description |
|---|---|
| Core Web Vitals | FCP, LCP, FID, CLS, INP, TTFB metrics |
| Performance Marks | Create and manage performance marks |
| Performance Measures | Measure duration between marks |
| PerformanceObserver | Subscribe to metric updates in real-time |
| Graceful Fallback | Safe no-op when Performance API is not available |
| Type | Description |
|---|---|
PerformanceMonitorInstance |
Instance returned by PerformanceMonitor.create() |
PerformanceMetrics |
Object containing Core Web Vitals metrics |
MetricType |
Metric types: 'fcp' | 'lcp' | 'fid' | 'cls' | 'inp' |
MetricHandler |
Callback function (value: number) => void |
CleanupFn |
Function to unsubscribe from metric updates |
Create a new performance monitor instance. Each instance has its own state (marks, measures, metric observers).
const monitor = PerformanceMonitor.create();Returns: PerformanceMonitorInstance
Check if the Performance API is available (static method).
if (PerformanceMonitor.isSupported()) {
const monitor = PerformanceMonitor.create();
}Returns: boolean - True if Performance API is available
Create a performance mark.
monitor.mark('api-call-start');
await fetchData();
monitor.mark('api-call-end');Parameters:
| Parameter | Type | Description |
|---|---|---|
name |
string |
Mark name |
Create a performance measure between two marks.
const measure = monitor.measure('api-call', 'api-call-start', 'api-call-end');
if (measure) {
console.log(`API call took ${measure.duration}ms`);
}Parameters:
| Parameter | Type | Description |
|---|---|---|
name |
string |
Measure name |
startMark |
string |
Start mark name (optional, defaults to navigation start) |
endMark |
string |
End mark name (optional, defaults to current time) |
Returns: PerformanceMeasure | undefined
Get current Core Web Vitals metrics.
const metrics = monitor.getMetrics();
// {
// fcp?: number, // First Contentful Paint (ms)
// lcp?: number, // Largest Contentful Paint (ms)
// fid?: number, // First Input Delay (ms)
// cls?: number, // Cumulative Layout Shift (unitless)
// inp?: number, // Interaction to Next Paint (ms)
// ttfb?: number // Time to First Byte (ms)
// }Returns: PerformanceMetrics - Object with available metrics
Get performance entries, optionally filtered by type.
// Get all entries
const allEntries = monitor.getEntries();
// Get navigation entries only
const navEntries = monitor.getEntries('navigation');
// Get resource timing entries
const resourceEntries = monitor.getEntries('resource');Parameters:
| Parameter | Type | Description |
|---|---|---|
type |
string |
Entry type filter (optional) |
Returns: PerformanceEntryList
Subscribe to metric updates using PerformanceObserver.
// Listen for LCP updates
const cleanup = monitor.onMetric('lcp', (value) => {
console.log('LCP:', value, 'ms');
analytics.track('lcp', { value });
});
// Listen for INP updates
const inpCleanup = monitor.onMetric('inp', (value) => {
console.log('INP:', value, 'ms');
});
// Later: cleanup when done
cleanup();
inpCleanup();Parameters:
| Parameter | Type | Description |
|---|---|---|
type |
MetricType |
Metric to observe: 'fcp' | 'lcp' | 'fid' | 'cls' | 'inp' |
handler |
MetricHandler |
Callback function (value: number) => void |
Returns: CleanupFn - Function to unsubscribe
Note: If a metric value is already available when subscribing, the handler is called immediately with the current value.
Clear performance marks.
// Clear specific mark
monitor.clearMarks('api-call-start');
// Clear all marks
monitor.clearMarks();Parameters:
| Parameter | Type | Description |
|---|---|---|
name |
string |
Mark name (optional, clears all if not provided) |
Clear performance measures.
// Clear specific measure
monitor.clearMeasures('api-call');
// Clear all measures
monitor.clearMeasures();Parameters:
| Parameter | Type | Description |
|---|---|---|
name |
string |
Measure name (optional, clears all if not provided) |
const monitor = PerformanceMonitor.create();
function measureAsync<T>(name: string, fn: () => Promise<T>): Promise<T> {
const startMark = `${name}-start`;
const endMark = `${name}-end`;
monitor.mark(startMark);
return fn().finally(() => {
monitor.mark(endMark);
const measure = monitor.measure(name, startMark, endMark);
if (measure) {
console.log(`${name}: ${measure.duration.toFixed(2)}ms`);
}
});
}
// Usage
const data = await measureAsync('fetch-users', () => fetch('/api/users'));function setupWebVitalsMonitoring() {
const monitor = PerformanceMonitor.create();
const cleanupFns: CleanupFn[] = [];
// Monitor all Core Web Vitals (including INP)
const metricTypes: MetricType[] = ['fcp', 'lcp', 'fid', 'cls', 'inp'];
for (const type of metricTypes) {
cleanupFns.push(
monitor.onMetric(type, (value) => {
sendToAnalytics(type, value);
})
);
}
// Return cleanup function
return () => cleanupFns.forEach((fn) => fn());
}const monitor = PerformanceMonitor.create();
function getPerformanceReport() {
const metrics = monitor.getMetrics();
const navEntries = monitor.getEntries(
'navigation'
) as PerformanceNavigationTiming[];
const resourceEntries = monitor.getEntries(
'resource'
) as PerformanceResourceTiming[];
return {
coreWebVitals: metrics,
navigation: navEntries[0],
resources: resourceEntries.map((r) => ({
name: r.name,
duration: r.duration,
transferSize: r.transferSize,
})),
};
}Each create() call returns an independent instance. Useful for isolating
metrics per module:
const apiMonitor = PerformanceMonitor.create();
const uiMonitor = PerformanceMonitor.create();
// Each instance tracks its own metrics independently
apiMonitor.onMetric('fcp', (v) => console.log('API FCP:', v));
uiMonitor.onMetric('lcp', (v) => console.log('UI LCP:', v));| Metric | Name | Description | Good Threshold |
|---|---|---|---|
| FCP | First Contentful Paint | Time until first content is painted | < 1.8s |
| LCP | Largest Contentful Paint | Time until largest content element is painted | < 2.5s |
| FID | First Input Delay | Time from first input to browser response | < 100ms |
| CLS | Cumulative Layout Shift | Sum of unexpected layout shift scores | < 0.1 |
| INP | Interaction to Next Paint | Worst interaction latency during page life | < 200ms |
| TTFB | Time to First Byte | Time until first byte of response received | < 800ms |
| Feature | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| Performance API | Yes | Yes | Yes | Yes |
| Performance Marks | Yes | Yes | Yes | Yes |
| Performance Measures | Yes | Yes | Yes | Yes |
| PerformanceObserver | Yes | Yes | Yes | Yes |
| Navigation Timing | Yes | Yes | Yes | Yes |
| Paint Timing (FCP) | Yes | Yes | Yes | Yes |
| LCP | Yes | No | No | Yes |
| FID | Yes | No | No | Yes |
| CLS | Yes | No | No | Yes |
Note: The module gracefully handles unsupported features by returning
undefined values or empty arrays.