Skip to content

Commit

Permalink
Add INP breakdown timings and LoAF attribution (#442)
Browse files Browse the repository at this point in the history
* Remove missed polyfill code

* Remove unused rollup plugin

* Add frame-based INP and LoAF attribution

* Add additional code comments

* Update src/types.ts

Co-authored-by: Barry Pollard <barrypollard@google.com>

* Update src/onINP.ts

Co-authored-by: Barry Pollard <barrypollard@google.com>

* Address review feedback

* Update README to match latest JSDocs

* Apply suggestions from code review

Co-authored-by: Barry Pollard <barrypollard@google.com>

* Address review feedback

* Add fallback for requestIdleCallback

* Add missing null check

* Rename processingTime to processingDuration

* Update tests to reduce flakiness

* Address review feedback

* Update type definitions and descriptions

* Update src/onINP.ts

Co-authored-by: Barry Pollard <barrypollard@google.com>

* Revert interactionType to be pointer or keyboard

* Increase the past renderTimes frame length

* Format code

* Update README.md

Co-authored-by: Brendan Kenny <bckenny@gmail.com>

* Update README

* Add test for LoAF entries

* Fix failing test

---------

Co-authored-by: Barry Pollard <barrypollard@google.com>
Co-authored-by: Brendan Kenny <bckenny@gmail.com>
  • Loading branch information
3 people committed Mar 29, 2024
1 parent 538cdf5 commit be20a19
Show file tree
Hide file tree
Showing 27 changed files with 901 additions and 454 deletions.
4 changes: 3 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"files": ["test/e2e/*.js"],
"globals": {
"$": false,
"browser": false
"browser": false,
"__toSafeObject": false
},
"extends": ["eslint:recommended"],
"rules": {
Expand Down Expand Up @@ -63,6 +64,7 @@
"node/no-missing-require": "off",
"node/shebang": "off",
"no-dupe-class-members": "off",
"prefer-spread": "off",
"space-before-function-paren": [
"error",
{
Expand Down
100 changes: 79 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

## Overview

The `web-vitals` library is a tiny (~1.5K, brotli'd), modular library for measuring all the [Web Vitals](https://web.dev/articles/vitals) metrics on real users, in a way that accurately matches how they're measured by Chrome and reported to other Google tools (e.g. [Chrome User Experience Report](https://developers.google.com/web/tools/chrome-user-experience-report), [Page Speed Insights](https://developers.google.com/speed/pagespeed/insights/), [Search Console's Speed Report](https://webmasters.googleblog.com/2019/11/search-console-speed-report.html)).
The `web-vitals` library is a tiny (~2K, brotli'd), modular library for measuring all the [Web Vitals](https://web.dev/articles/vitals) metrics on real users, in a way that accurately matches how they're measured by Chrome and reported to other Google tools (e.g. [Chrome User Experience Report](https://developers.google.com/web/tools/chrome-user-experience-report), [Page Speed Insights](https://developers.google.com/speed/pagespeed/insights/), [Search Console's Speed Report](https://webmasters.googleblog.com/2019/11/search-console-speed-report.html)).

The library supports all of the [Core Web Vitals](https://web.dev/articles/vitals#core_web_vitals) as well as a number of other metrics that are useful in diagnosing [real-user](https://web.dev/articles/user-centric-performance-metrics) performance issues.

Expand Down Expand Up @@ -442,14 +442,14 @@ The following table lists all the builds distributed with the `web-vitals` packa
<td><code>web-vitals.umd.cjs</code></td>
<td><code>pkg.main</code></td>
<td>
A UMD version of the <code>web-vitals.js</code> bundle (exposed on the <code>window.webVitals.*</code> namespace).
A UMD version of the <code>web-vitals.js</code> bundle (exposed on the <code>self.webVitals.*</code> namespace).
</td>
</tr>
<tr>
<td><code>web-vitals.iife.js</code></td>
<td>--</td>
<td>
An IIFE version of the <code>web-vitals.js</code> bundle (exposed on the <code>window.webVitals.*</code> namespace).
An IIFE version of the <code>web-vitals.js</code> bundle (exposed on the <code>self.webVitals.*</code> namespace).
</td>
</tr>
<tr>
Expand All @@ -463,15 +463,15 @@ The following table lists all the builds distributed with the `web-vitals` packa
<td><code>web-vitals.attribution.umd.cjs</code></td>
<td>--</td>
<td>
A UMD version of the <code>web-vitals.attribution.js</code> build (exposed on the <code>window.webVitals.*</code> namespace).
A UMD version of the <code>web-vitals.attribution.js</code> build (exposed on the <code>self.webVitals.*</code> namespace).
</td>
</tr>
</tr>
<tr>
<td><code>web-vitals.attribution.iife.js</code></td>
<td>--</td>
<td>
An IIFE version of the <code>web-vitals.attribution.js</code> build (exposed on the <code>window.webVitals.*</code> namespace).
An IIFE version of the <code>web-vitals.attribution.js</code> build (exposed on the <code>self.webVitals.*</code> namespace).
</td>
</tr>
</table>
Expand Down Expand Up @@ -877,31 +877,89 @@ interface FIDAttribution {
```ts
interface INPAttribution {
/**
* A selector identifying the element that the user interacted with for
* the event corresponding to INP. This element will be the `target` of the
* `event` dispatched.
* A selector identifying the element that the user first interacted with
* as part of the frame where the INP candidate interaction occurred.
* If `interactionTarget` is an empty string, that generally means the
* element was removed from the DOM after the interaction.
*/
eventTarget?: string;
interactionTarget: string;

/**
* The time when the user interacted for the event corresponding to INP.
* This time will match the `timeStamp` value of the `event` dispatched.
* The time when the user first interacted during the frame where the INP
* candidate interaction occurred (if more than one interaction occurred
* within the frame, only the first time is reported).
*/
eventTime?: number;
interactionTime: DOMHighResTimeStamp;

/**
* The `type` of the `event` dispatched corresponding to INP.
* The best-guess timestamp of the next paint after the interaction.
* In general, this timestamp is the same as the `startTime + duration` of
* the event timing entry. However, since `duration` values are rounded to
* the nearest 8ms, it can sometimes appear that the paint occurred before
* processing ended (which cannot happen). This value clamps the paint time
* so it's always after `processingEnd` from the Event Timing API and
* `renderStart` from the Long Animation Frame API (where available).
* It also averages the duration values for all entries in the same
* animation frame, which should be closer to the "real" value.
*/
eventType?: string;
nextPaintTime: DOMHighResTimeStamp;

/**
* The `PerformanceEventTiming` entry corresponding to INP.
* The type of interaction, based on the event type of the `event` entry
* that corresponds to the interaction (i.e. the first `event` entry
* containing an `interactionId` dispatched in a given animation frame).
* For "pointerdown", "pointerup", or "click" events this will be "pointer",
* and for "keydown" or "keyup" events this will be "keyboard".
*/
eventEntry?: PerformanceEventTiming;
interactionType: 'pointer' | 'keyboard';

/**
* The loading state of the document at the time when the even corresponding
* to INP occurred (see `LoadState` for details). If the interaction occurred
* while the document was loading and executing script (e.g. usually in the
* `dom-interactive` phase) it can result in long delays.
* An array of Event Timing entries that were processed within the same
* animation frame as the INP candidate interaction.
*/
loadState?: LoadState;
processedEventEntries: PerformanceEventTiming[];

/**
* If the browser supports the Long Animation Frame API, this array will
* include any `long-animation-frame` entries that intersect with the INP
* candidate interaction's `startTime` and the `processingEnd` time of the
* last event processed within that animation frame. If the browser does not
* support the Long Animation Frame API or no `long-animation-frame` entries
* are detect, this array will be empty.
*/
longAnimationFrameEntries: PerformanceLongAnimationFrameTiming[];

/**
* The time from when the user interacted with the page until when the
* browser was first able to start processing event listeners for that
* interaction. This time captures the delay before event processing can
* begin due to the main thread being busy with other work.
*/
inputDelay: number;

/**
* The time from when the first event listener started running in response to
* the user interaction until when all event listener processing has finished.
*/
processingDuration: number;

/**
* The time from when the browser finished processing all event listeners for
* the user interaction until the next frame is presented on the screen and
* visible to the user. This time includes work on the main thread (such as
* `requestAnimationFrame()` callbacks, `ResizeObserver` and
* `IntersectionObserver` callbacks, and style/layout calculation) as well
* as off-main-thread work (such as compositor, GPU, and raster work).
*/
presentationDelay: number;

/**
* The loading state of the document at the time when the interaction
* corresponding to INP occurred (see `LoadState` for details). If the
* interaction occurred while the document was loading and executing script
* (e.g. usually in the `dom-interactive` phase) it can result in long delays.
*/
loadState: LoadState;
}
```

Expand Down
Loading

0 comments on commit be20a19

Please sign in to comment.