Understand your Angular application's real-world performance with Firebase Performance Monitoring. Performance Monitoring automatically provides a trace for page load when you add AngularFirePerformanceModule
into your App Module's imports.
import { AngularFireModule } from '@angular/fire';
import { AngularFirePerformanceModule } from '@angular/fire/performance';
import { environment } from '../environments/environment';
@NgModule({
imports: [
BrowserModule,
AngularFireModule.initializeApp(environment.firebase),
AngularFirePerformanceModule,
...
],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule {}
The page load trace breaks down into the following default metrics:
- first paint traces — measure the time between when the user navigates to a page and when any visual change happens
- first contentful paint traces — measure the time between when a user navigates to a page and when meaningful content displays, like an image or text
- domInteractive traces — measure the time between when the user navigates to a page and when the page is considered interactive for the user
- domContentLoadedEventEnd traces — measure the time between when the user navigates to a page and when the initial HTML document is completely loaded and parsed
- loadEventEnd traces — measure the time between when the user navigates to the page and when the current document's load event completes
- first input delay traces — measure the time between when the user interacts with a page and when the browser is able to respond to that input
- Angular specific traces - measure the time needed for
ApplicationRef.isStable
to be true, an important metric to track if you're concerned about solving Zone.js issues for proper functionality of NGSW and Server Side Rendering
First Input Delay (FID) measures the time from when a user first interacts with your site (i.e. when they click a link, tap on a button, or use a custom, JavaScript-powered control) to the time when the browser is actually able to respond to that interaction. See the article on the Google Developer's Blog for more information on FID.
In order to track first input delay, you'll want to polyfill the browser performance API:
npm install --save-dev first-input-delay
Then add import 'first-input-delay';
to your src/polyfills.ts
.
You can inject AngularFirePerformance
to perform manual traces on Observables.
constructor(private afp: AngularFirePerformance, private afs: AngularFirestore) {}
ngOnInit() {
this.articles = afs.collection('articles')
.collection('articles', ref => ref.orderBy('publishedAt', 'desc'))
.snapshotChanges()
.pipe(
// measure the amount of time between the Observable being subscribed to and first emission (or completion)
this.afp.trace('getArticles'),
map(articles => ...)
);
}
The most basic operator, trace
will measure the amount of time it takes for your observable to either complete or emit its first value. Beyond the basic trace there are several other operators:
Trace the observable until the first emission that passes the provided test.
If the orComplete
option is passed it will complete the trace when the observable completes, even if an emission never passed the provided test.
Starting with an emission that passes the provided test, trace until an emission fails the test.
If the orComplete
option is passed it will complete any existing trace when the observable completes.
Trace the observable until completion.
Traces the observable until the first emission.
By default, AngularFirePerformanceModule
traces your Angular application's time to ApplicationRef.isStable
. isStable
is an important metric to track if you're concerned about proper functionality of NGSW and Server Side Rendering. If you want to opt-out of the tracing of this metric use the AUTOMATICALLY_TRACE_CORE_NG_METRICS
injection token:
import { NgModule } from '@angular/core';
import { AngularFirePerformanceModule, AUTOMATICALLY_TRACE_CORE_NG_METRICS } from '@angular/fire/functions';
@NgModule({
imports: [
...
AngularFirePerformanceModule,
...
],
...
providers: [
{ provide: AUTOMATICALLY_TRACE_CORE_NG_METRICS, useValue: false }
]
})
export class AppModule {}
Similarly, setting INSTRUMENTATION_ENABLED
or DATA_COLLECTION_ENABLED
to false disable all automatic and custom traces respectively.
trace$(name:string)
provides an observable version of firebase/perf
's .trace
method; the basis for AngularFirePerfomance
's pipes.
.subscribe()
is equivalent to calling .start()
.unsubscribe()
is equivalent to calling .stop()
TraceOptions
can be provided to the aformentioned operators to collect custom metrics and attributes on your traces:
type TraceOptions = {
metrics?: { [key:string]: number },
attributes?: { [key:string]: string },
attribute$?: { [key:string]: Observable<string> },
incrementMetric$: { [key:string]: Observable<number|void|null|undefined> },
metric$?: { [key:string]: Observable<number> }
};
const articleLength$ = this.articles.pipe(
map(actions => actions.length)
);
const articleSize$ = this.articles.pipe(
map(actions => actions.reduce((sum, a) => sum += JSON.stringify(a.payload.doc.data()).length))
)
this.articles = afs.collection('articles')
.collection('articles', ref => ref.orderBy('publishedAt', 'desc'))
.snapshotChanges()
.pipe(
this.afp.trace('getArticles', {
attributes: { gitSha: '1d277f823ad98dd739fb86e9a6c440aa8237ff3a' },
metrics: { something: 42 },
metrics$: { count: articleLength$, size: articleSize$ },
attributes$: { user: this.afAuth.user },
incrementMetric$: { buttonClicks: fromEvent(button, 'click') }
}),
share()
);