diff --git a/packages/tracing/src/browser/metrics.ts b/packages/tracing/src/browser/metrics.ts index 94e14272dbb3..d7bfd434ba5c 100644 --- a/packages/tracing/src/browser/metrics.ts +++ b/packages/tracing/src/browser/metrics.ts @@ -9,7 +9,6 @@ import { msToSec } from '../utils'; import { getCLS, LayoutShift } from './web-vitals/getCLS'; import { getFID } from './web-vitals/getFID'; import { getLCP, LargestContentfulPaint } from './web-vitals/getLCP'; -import { getUpdatedCLS } from './web-vitals/getUpdatedCLS'; import { getVisibilityWatcher } from './web-vitals/lib/getVisibilityWatcher'; import { NavigatorDeviceMemory, NavigatorNetworkInformation } from './web-vitals/types'; @@ -22,7 +21,6 @@ export class MetricsInstrumentation { private _performanceCursor: number = 0; private _lcpEntry: LargestContentfulPaint | undefined; private _clsEntry: LayoutShift | undefined; - private _updatedClsEntry: LayoutShift | undefined; public constructor() { if (!isNodeEnv() && global?.performance) { @@ -189,10 +187,10 @@ export class MetricsInstrumentation { }); } - // If FCP is not recorded we should not record the updated cls value + // If FCP is not recorded we should not record the cls value // according to the new definition of CLS. if (!('fcp' in this._measurements)) { - delete this._measurements['updated-cls']; + delete this._measurements.cls; } transaction.setMeasurements(this._measurements); @@ -229,17 +227,13 @@ export class MetricsInstrumentation { transaction.setTag(`cls.source.${index + 1}`, htmlTreeAsString(source.node)), ); } - - if (this._updatedClsEntry && this._updatedClsEntry.sources) { - logger.log('[Measurements] Adding Updated CLS Data'); - this._updatedClsEntry.sources.forEach((source, index) => - transaction.setTag(`updated-cls.source.${index + 1}`, htmlTreeAsString(source.node)), - ); - } } /** Starts tracking the Cumulative Layout Shift on the current page. */ private _trackCLS(): void { + // See: + // https://web.dev/evolving-cls/ + // https://web.dev/cls-web-tooling/ getCLS(metric => { const entry = metric.entries.pop(); if (!entry) { @@ -250,20 +244,6 @@ export class MetricsInstrumentation { this._measurements['cls'] = { value: metric.value }; this._clsEntry = entry as LayoutShift; }); - - // See: - // https://web.dev/evolving-cls/ - // https://web.dev/cls-web-tooling/ - getUpdatedCLS(metric => { - const entry = metric.entries.pop(); - if (!entry) { - return; - } - - logger.log('[Measurements] Adding Updated CLS'); - this._measurements['updated-cls'] = { value: metric.value }; - this._updatedClsEntry = entry as LayoutShift; - }); } /** diff --git a/packages/tracing/src/browser/web-vitals/getCLS.ts b/packages/tracing/src/browser/web-vitals/getCLS.ts index 7e3307ce3115..ef73ceb3aee0 100644 --- a/packages/tracing/src/browser/web-vitals/getCLS.ts +++ b/packages/tracing/src/browser/web-vitals/getCLS.ts @@ -38,12 +38,40 @@ export const getCLS = (onReport: ReportHandler, reportAllChanges?: boolean): voi const metric = initMetric('CLS', 0); let report: ReturnType; + let sessionValue = 0; + let sessionEntries: PerformanceEntry[] = []; + const entryHandler = (entry: LayoutShift): void => { + // Only count layout shifts without recent user input. + // TODO: Figure out why entry can be undefined if (entry && !entry.hadRecentInput) { - (metric.value as number) += entry.value; - metric.entries.push(entry); - if (report) { - report(); + const firstSessionEntry = sessionEntries[0]; + const lastSessionEntry = sessionEntries[sessionEntries.length - 1]; + + // If the entry occurred less than 1 second after the previous entry and + // less than 5 seconds after the first entry in the session, include the + // entry in the current session. Otherwise, start a new session. + if ( + sessionValue && + sessionEntries.length !== 0 && + entry.startTime - lastSessionEntry.startTime < 1000 && + entry.startTime - firstSessionEntry.startTime < 5000 + ) { + sessionValue += entry.value; + sessionEntries.push(entry); + } else { + sessionValue = entry.value; + sessionEntries = [entry]; + } + + // If the current session value is larger than the current CLS value, + // update CLS and the entries contributing to it. + if (sessionValue > metric.value) { + metric.value = sessionValue; + metric.entries = sessionEntries; + if (report) { + report(); + } } } }; diff --git a/packages/tracing/src/browser/web-vitals/getUpdatedCLS.ts b/packages/tracing/src/browser/web-vitals/getUpdatedCLS.ts deleted file mode 100644 index 5f5673a67ae1..000000000000 --- a/packages/tracing/src/browser/web-vitals/getUpdatedCLS.ts +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { bindReporter } from './lib/bindReporter'; -import { initMetric } from './lib/initMetric'; -import { observe, PerformanceEntryHandler } from './lib/observe'; -import { onHidden } from './lib/onHidden'; -import { ReportHandler } from './types'; - -// https://wicg.github.io/layout-instability/#sec-layout-shift -export interface LayoutShift extends PerformanceEntry { - value: number; - hadRecentInput: boolean; - sources: Array; - toJSON(): Record; -} - -export interface LayoutShiftAttribution { - node?: Node; - previousRect: DOMRectReadOnly; - currentRect: DOMRectReadOnly; -} - -export const getUpdatedCLS = (onReport: ReportHandler, reportAllChanges?: boolean): void => { - const metric = initMetric('UpdatedCLS', 0); - let report: ReturnType; - - let sessionValue = 0; - let sessionEntries: PerformanceEntry[] = []; - - const entryHandler = (entry: LayoutShift): void => { - // Only count layout shifts without recent user input. - // TODO: Figure out why entry can be undefined - if (entry && !entry.hadRecentInput) { - const firstSessionEntry = sessionEntries[0]; - const lastSessionEntry = sessionEntries[sessionEntries.length - 1]; - - // If the entry occurred less than 1 second after the previous entry and - // less than 5 seconds after the first entry in the session, include the - // entry in the current session. Otherwise, start a new session. - if ( - sessionValue && - sessionEntries.length !== 0 && - entry.startTime - lastSessionEntry.startTime < 1000 && - entry.startTime - firstSessionEntry.startTime < 5000 - ) { - sessionValue += entry.value; - sessionEntries.push(entry); - } else { - sessionValue = entry.value; - sessionEntries = [entry]; - } - - // If the current session value is larger than the current CLS value, - // update CLS and the entries contributing to it. - if (sessionValue > metric.value) { - metric.value = sessionValue; - metric.entries = sessionEntries; - if (report) { - report(); - } - } - } - }; - - const po = observe('layout-shift', entryHandler as PerformanceEntryHandler); - if (po) { - report = bindReporter(onReport, metric, reportAllChanges); - - onHidden(() => { - po.takeRecords().map(entryHandler as PerformanceEntryHandler); - report(true); - }); - } -};