Primitives for collecting browser performance metrics.
$ yarn add @shopify/performance
This library wraps around the native Performance
and PerformanceObserver
browser globals, providing a normalized interface for tracking performance across browsers. It also adds the notion of "navigations": sections of time spent navigating to a "complete" page, during which events (time to first byte, script downloads, GraphQL queries, etc) occur. Finally, it provides a few event listeners to be informed of new navigation and key events.
To start using this library, construct an instance of the Performance
class. Only one instance of this class should exist during the lifecycle of your app, as this class assumes it is constructed near the page’s initial load.
import {Performance} from '@shopify/performance';
const performance = new Performance();
If you want to listen for events, you can use the on
method. There are three events you can listen for:
// Listen for completed navigations. If you call this after the initial load
// "navigation", your handler will immediately be invoked with that object.
performance.on('navigation', navigation => {});
// Listen for the start of new navigations.
performance.on('inflightNavigation', () => {});
// Listen for "lifecycle" events; that is, those that are part of the initial
// page load and come directly from the browser. These are events like time
// to first byte and time to first paint. See the `LifecycleEvent` type for
// the full set of possible events. If you add your listener after some of these
// events have been triggered, it will immediately be invoked once for each
// previously-triggered event.
performance.on('lifecycleEvent', event => {});
The on
method returns a clean-up function that you can invoke when you're done listening on the event:
const cleanupNavigationListener = performance.on(
'navigation',
navigation => {},
);
cleanupNavigationListener();
You can also manage navigations using this object. Calling performance.start()
will begin a new navigation, cancelling any that are currently inflight. performance.event()
allows you to register custom events on the navigation. Finally, performance.finish()
marks the navigation is complete.
import {now} from '@shopify/performance';
// You usually don't need this, as we automatically start a visit when the
// browser first loads, and when the history API is used to navigate the app.
performance.start({
target: '/my-page',
});
// A duration of 0 indicates a mark of some kind, while a non-0 duration would
// be used for things like network requests. Make sure to use the `now()` function
// because it will use high-resolution time when available.
performance.event({
type: 'customevent',
start: now(),
duration: 0,
});
performance.finish();
The Navigation
object represents a full navigation, either from a full-page refresh, or between two pages. It has the following key details about the navigation:
start
: the full timestamp when the navigation started, using high-resolution time when available.duration
: how long the navigation took, using high-resolution time when available.target
: a string representing the "end" of the navigation, defaulting to the target page’s pathname.result
: aNavigationResult
marking the navigation as either finished, cancelled (another navigation began before this one completed), or timed out (performance.finish()
was not called in a reasonable amount of time, which defaults to 60 seconds from whenperformance.start()
is called)metadata
: an object giving additional context to the navigation. This object has the following properties:index
(the number of navigations before this one since the last full page navigation)supportsDetailedEvents
(whether events like time to first paint are supported by the browser)supportsDetailedTime
(whether high-resolution time is supported by the browser)
events
: an array of objects representing the events that occurred during the navigation. These events include the following properties:type
: the type of eventstart
: when the event started, relative to the start of the navigationduration
: how long the event took (0 indicates a mark, rather than an event occurring over time)metadata
: an object with arbitrary key-value pairs providing additional context
Navigation
also provides a number of utility methods for gathering more actionable information, such as eventsByType
for filtering events to a particular type, or totalDownloadSize
for the cumulative size of all requested resources. Please consult the TypeScript definitions for a full listing of these methods.
The Performance
and Navigation
classes both deal with Event
objects with which contain information about the timing of specific milestones during the course of a user's browser session in milliseconds.
The time until the server sends the first part of the response. Learn more about time to First Byte.
The time until the browser renders anything that differs from the previous page. Learn more about first paint.
The time until the browser renders the first bit of content from the DOM. Learn more about this first Contentful Paint.
The time until the DOM has been entirely loaded and parsed. Learn more about DOM Content Loaded.
The time from when a user first interacts with your site to the time when the browser is able to respond to that interaction. Learn more about first Input Delay.
The time until the DOM and all its styles and synchronous scripts have loaded. Learn more about load Event.
Any task that take 50 milliseconds or more. Learn more about long task.
The time spent downloading a script resource.
This event will also log the name and size of the resource as metadata
.
The time spent downloading a style resource.
This event will also log the name and size of the resource as metadata
.
The time spent resolving GraphQL queries during the navigation.
This metric needs to be manually set up in Apollo Client. The setup can be done as a ApolloLink.
The time between navigation start and the first time a @shopify/react-performance
's <PerformanceMark stage="usable" />
component is rendered.