Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save a reference to the LCP and CLS targets in case they are removed from the DOM #562

Open
wants to merge 20 commits into
base: v5
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions src/attribution/onLCP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,20 @@

import {getNavigationEntry} from '../lib/getNavigationEntry.js';
import {getSelector} from '../lib/getSelector.js';
import {onLCP as unattributedOnLCP} from '../onLCP.js';
import {
onLCP as unattributedOnLCP,
entryPreProcessingCallbacks,
} from '../onLCP.js';
import {
LCPAttribution,
LCPMetric,
LCPMetricWithAttribution,
ReportOpts,
} from '../types.js';

// A reference to the LCP Target node incase it is removed before reporting
tunetheweb marked this conversation as resolved.
Show resolved Hide resolved
let lcpTargetNode: Node;
tunetheweb marked this conversation as resolved.
Show resolved Hide resolved

const attributeLCP = (metric: LCPMetric): LCPMetricWithAttribution => {
// Use a default object if no other attribution has been set.
let attribution: LCPAttribution = {
Expand Down Expand Up @@ -65,7 +71,7 @@ const attributeLCP = (metric: LCPMetric): LCPMetricWithAttribution => {
);

attribution = {
element: getSelector(lcpEntry.element),
element: getSelector(lcpEntry.element || lcpTargetNode),
timeToFirstByte: ttfb,
resourceLoadDelay: lcpRequestStart - ttfb,
resourceLoadDuration: lcpResponseEnd - lcpRequestStart,
Expand All @@ -92,6 +98,16 @@ const attributeLCP = (metric: LCPMetric): LCPMetricWithAttribution => {
return metricWithAttribution;
};

// Get a reference to the LCP target element in case it's removed from the DOM
// later.
const saveLCPTarget = (lcpEntry: LargestContentfulPaint) => {
if (lcpEntry.element) {
lcpTargetNode = lcpEntry.element;
}
};

entryPreProcessingCallbacks.push(saveLCPTarget);

/**
* Calculates the [LCP](https://web.dev/articles/lcp) value for the current page and
* calls the `callback` function once the value is ready (along with the
Expand Down
9 changes: 9 additions & 0 deletions src/onLCP.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ import {LCPMetric, MetricRatingThresholds, ReportOpts} from './types.js';
/** Thresholds for LCP. See https://web.dev/articles/lcp#what_is_a_good_lcp_score */
export const LCPThresholds: MetricRatingThresholds = [2500, 4000];

interface EntryPreProcessingHook {
(entry: LargestContentfulPaint): void;
}

export const entryPreProcessingCallbacks: EntryPreProcessingHook[] = [];

/**
* Calculates the [LCP](https://web.dev/articles/lcp) value for the current page and
* calls the `callback` function once the value is ready (along with the
Expand Down Expand Up @@ -57,6 +63,9 @@ export const onLCP = (
}

for (const entry of entries) {
for (const cb of entryPreProcessingCallbacks) {
cb(entry);
}
// Only report if the page wasn't hidden prior to LCP.
if (entry.startTime < visibilityWatcher.firstHiddenTime) {
// The startTime attribute returns the value of the renderTime if it is
Expand Down