@paulirish/trace_engine 0.0.60 → 0.0.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.tmp/tsbuildinfo/tsconfig.tsbuildinfo +1 -1
- package/generated/protocol.d.ts +10 -9
- package/locales/af.json +9 -0
- package/locales/am.json +10 -1
- package/locales/ar.json +20 -11
- package/locales/as.json +9 -0
- package/locales/az.json +10 -1
- package/locales/be.json +9 -0
- package/locales/bg.json +9 -0
- package/locales/bn.json +9 -0
- package/locales/bs.json +10 -1
- package/locales/ca.json +9 -0
- package/locales/cs.json +9 -0
- package/locales/cy.json +10 -1
- package/locales/da.json +9 -0
- package/locales/de.json +9 -0
- package/locales/el.json +9 -0
- package/locales/en-GB.json +9 -0
- package/locales/en-US.json +18 -18
- package/locales/en-XL.json +18 -18
- package/locales/es-419.json +9 -0
- package/locales/es.json +9 -0
- package/locales/et.json +9 -0
- package/locales/eu.json +10 -1
- package/locales/fa.json +11 -2
- package/locales/fi.json +9 -0
- package/locales/fil.json +9 -0
- package/locales/fr-CA.json +10 -1
- package/locales/fr.json +9 -0
- package/locales/gl.json +9 -0
- package/locales/gu.json +9 -0
- package/locales/he.json +32 -23
- package/locales/hi.json +9 -0
- package/locales/hr.json +9 -0
- package/locales/hu.json +9 -0
- package/locales/hy.json +9 -0
- package/locales/id.json +9 -0
- package/locales/is.json +9 -0
- package/locales/it.json +9 -0
- package/locales/ja.json +9 -0
- package/locales/ka.json +10 -1
- package/locales/kk.json +9 -0
- package/locales/km.json +10 -1
- package/locales/kn.json +11 -2
- package/locales/ko.json +10 -1
- package/locales/ky.json +9 -0
- package/locales/lo.json +10 -1
- package/locales/lt.json +9 -0
- package/locales/lv.json +10 -1
- package/locales/mk.json +9 -0
- package/locales/ml.json +11 -2
- package/locales/mn.json +9 -0
- package/locales/mr.json +9 -0
- package/locales/ms.json +9 -0
- package/locales/my.json +11 -2
- package/locales/ne.json +9 -0
- package/locales/nl.json +9 -0
- package/locales/no.json +9 -0
- package/locales/or.json +9 -0
- package/locales/pa.json +9 -0
- package/locales/pl.json +9 -0
- package/locales/pt-PT.json +9 -0
- package/locales/pt.json +9 -0
- package/locales/ro.json +10 -1
- package/locales/ru.json +9 -0
- package/locales/si.json +9 -0
- package/locales/sk.json +9 -0
- package/locales/sl.json +9 -0
- package/locales/sq.json +10 -1
- package/locales/sr-Latn.json +9 -0
- package/locales/sr.json +9 -0
- package/locales/sv.json +9 -0
- package/locales/sw.json +9 -0
- package/locales/ta.json +9 -0
- package/locales/te.json +10 -1
- package/locales/th.json +9 -0
- package/locales/tr.json +9 -0
- package/locales/uk.json +9 -0
- package/locales/ur.json +10 -1
- package/locales/uz.json +9 -0
- package/locales/vi.json +9 -0
- package/locales/zh-HK.json +9 -0
- package/locales/zh-TW.json +10 -1
- package/locales/zh.json +9 -0
- package/locales/zu.json +9 -0
- package/models/trace/extras/extras.d.ts +0 -3978
- package/models/trace/extras/extras.js +0 -3978
- package/models/trace/handlers/UserTimingsHandler.d.ts +1 -1
- package/models/trace/handlers/UserTimingsHandler.js +1 -1
- package/models/trace/handlers/UserTimingsHandler.js.map +1 -1
- package/models/trace/insights/CLSCulprits.d.ts +1 -1
- package/models/trace/insights/CLSCulprits.js +2 -1
- package/models/trace/insights/CLSCulprits.js.map +1 -1
- package/models/trace/insights/Cache.d.ts +1 -1
- package/models/trace/insights/Cache.js +2 -1
- package/models/trace/insights/Cache.js.map +1 -1
- package/models/trace/insights/DOMSize.d.ts +1 -1
- package/models/trace/insights/DOMSize.js +2 -1
- package/models/trace/insights/DOMSize.js.map +1 -1
- package/models/trace/insights/DocumentLatency.d.ts +1 -1
- package/models/trace/insights/DocumentLatency.js +2 -1
- package/models/trace/insights/DocumentLatency.js.map +1 -1
- package/models/trace/insights/DuplicatedJavaScript.d.ts +1 -1
- package/models/trace/insights/DuplicatedJavaScript.js +2 -1
- package/models/trace/insights/DuplicatedJavaScript.js.map +1 -1
- package/models/trace/insights/FontDisplay.d.ts +1 -1
- package/models/trace/insights/FontDisplay.js +2 -1
- package/models/trace/insights/FontDisplay.js.map +1 -1
- package/models/trace/insights/ForcedReflow.d.ts +1 -1
- package/models/trace/insights/ForcedReflow.js +2 -1
- package/models/trace/insights/ForcedReflow.js.map +1 -1
- package/models/trace/insights/INPBreakdown.d.ts +1 -1
- package/models/trace/insights/INPBreakdown.js +2 -1
- package/models/trace/insights/INPBreakdown.js.map +1 -1
- package/models/trace/insights/ImageDelivery.d.ts +1 -1
- package/models/trace/insights/ImageDelivery.js +2 -1
- package/models/trace/insights/ImageDelivery.js.map +1 -1
- package/models/trace/insights/LCPBreakdown.d.ts +1 -1
- package/models/trace/insights/LCPBreakdown.js +2 -1
- package/models/trace/insights/LCPBreakdown.js.map +1 -1
- package/models/trace/insights/LCPDiscovery.d.ts +1 -1
- package/models/trace/insights/LCPDiscovery.js +2 -1
- package/models/trace/insights/LCPDiscovery.js.map +1 -1
- package/models/trace/insights/LegacyJavaScript.d.ts +1 -1
- package/models/trace/insights/LegacyJavaScript.js +2 -1
- package/models/trace/insights/LegacyJavaScript.js.map +1 -1
- package/models/trace/insights/ModernHTTP.d.ts +1 -1
- package/models/trace/insights/ModernHTTP.js +2 -1
- package/models/trace/insights/ModernHTTP.js.map +1 -1
- package/models/trace/insights/NetworkDependencyTree.d.ts +1 -1
- package/models/trace/insights/NetworkDependencyTree.js +2 -1
- package/models/trace/insights/NetworkDependencyTree.js.map +1 -1
- package/models/trace/insights/RenderBlocking.js +2 -1
- package/models/trace/insights/RenderBlocking.js.map +1 -1
- package/models/trace/insights/SlowCSSSelector.d.ts +1 -1
- package/models/trace/insights/SlowCSSSelector.js +2 -1
- package/models/trace/insights/SlowCSSSelector.js.map +1 -1
- package/models/trace/insights/ThirdParties.js +2 -1
- package/models/trace/insights/ThirdParties.js.map +1 -1
- package/models/trace/insights/Viewport.d.ts +1 -1
- package/models/trace/insights/Viewport.js +2 -1
- package/models/trace/insights/Viewport.js.map +1 -1
- package/models/trace/insights/types.d.ts +2 -1
- package/models/trace/insights/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -29,7 +29,7 @@ export interface UserTimingsData {
|
|
|
29
29
|
}
|
|
30
30
|
export declare function reset(): void;
|
|
31
31
|
/**
|
|
32
|
-
* Similar to the default {@
|
|
32
|
+
* Similar to the default {@link Helpers.Trace.eventTimeComparator}
|
|
33
33
|
* but with a twist:
|
|
34
34
|
* In case of equal start and end times, put the second event (within a
|
|
35
35
|
* track) first.
|
|
@@ -108,7 +108,7 @@ function getEventTrack(event) {
|
|
|
108
108
|
return undefined;
|
|
109
109
|
}
|
|
110
110
|
/**
|
|
111
|
-
* Similar to the default {@
|
|
111
|
+
* Similar to the default {@link Helpers.Trace.eventTimeComparator}
|
|
112
112
|
* but with a twist:
|
|
113
113
|
* In case of equal start and end times, put the second event (within a
|
|
114
114
|
* track) first.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserTimingsHandler.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/handlers/UserTimingsHandler.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2022 The Chromium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\n/**\n * IMPORTANT!\n * See UserTimings.md in this directory for some handy documentation on\n * UserTimings and the trace events we parse currently.\n **/\nlet syntheticEvents: Array<Types.Events.SyntheticEventPair<Types.Events.PairableAsync>> = [];\n\n// There are two events dispatched for performance.measure calls: one to\n// represent the measured timing in the tracing clock (which we type as\n// PerformanceMeasure) and another one for the call itself (which we\n// type as UserTimingMeasure). The two events corresponding to the same\n// call are linked together by a common trace_id. The reason two events\n// are dispatched is because the first was originally added with the\n// implementation of the performance.measure API and it uses an\n// overridden timestamp and duration. To prevent breaking potential deps\n// created since then, a second event was added instead of changing the\n// params of the first.\nlet measureTraceByTraceId = new Map<number, Types.Events.UserTimingMeasure>();\nlet performanceMeasureEvents: Types.Events.PerformanceMeasure[] = [];\nlet performanceMarkEvents: Types.Events.PerformanceMark[] = [];\n\nlet consoleTimings: Array<Types.Events.ConsoleTimeBegin|Types.Events.ConsoleTimeEnd> = [];\n\nlet timestampEvents: Types.Events.ConsoleTimeStamp[] = [];\n\nexport interface UserTimingsData {\n /**\n * Events triggered with the performance.measure() API.\n * https://developer.mozilla.org/en-US/docs/Web/API/Performance/measure\n */\n performanceMeasures: readonly Types.Events.SyntheticUserTimingPair[];\n /**\n * Events triggered with the performance.mark() API.\n * https://developer.mozilla.org/en-US/docs/Web/API/Performance/mark\n */\n performanceMarks: readonly Types.Events.PerformanceMark[];\n /**\n * Events triggered with the console.time(), console.timeEnd() and\n * console.timeLog() API.\n * https://developer.mozilla.org/en-US/docs/Web/API/console/time\n */\n consoleTimings: readonly Types.Events.SyntheticConsoleTimingPair[];\n /**\n * Events triggered with the console.timeStamp() API\n * https://developer.mozilla.org/en-US/docs/Web/API/console/timeStamp\n */\n timestampEvents: readonly Types.Events.ConsoleTimeStamp[];\n /**\n * Events triggered to trace the call to performance.measure itself,\n * cached by trace_id.\n */\n measureTraceByTraceId: Map<number, Types.Events.UserTimingMeasure>;\n}\n\nexport function reset(): void {\n syntheticEvents = [];\n performanceMeasureEvents = [];\n performanceMarkEvents = [];\n consoleTimings = [];\n timestampEvents = [];\n measureTraceByTraceId = new Map();\n}\n\nconst resourceTimingNames = [\n 'workerStart',\n 'redirectStart',\n 'redirectEnd',\n 'fetchStart',\n 'domainLookupStart',\n 'domainLookupEnd',\n 'connectStart',\n 'connectEnd',\n 'secureConnectionStart',\n 'requestStart',\n 'responseStart',\n 'responseEnd',\n];\nconst navTimingNames = [\n 'navigationStart',\n 'unloadEventStart',\n 'unloadEventEnd',\n 'redirectStart',\n 'redirectEnd',\n 'fetchStart',\n 'commitNavigationEnd',\n 'domainLookupStart',\n 'domainLookupEnd',\n 'connectStart',\n 'connectEnd',\n 'secureConnectionStart',\n 'requestStart',\n 'responseStart',\n 'responseEnd',\n 'domLoading',\n 'domInteractive',\n 'domContentLoadedEventStart',\n 'domContentLoadedEventEnd',\n 'domComplete',\n 'loadEventStart',\n 'loadEventEnd',\n];\n// These are events dispatched under the blink.user_timing category\n// but that the user didn't add. Filter them out so that they do not\n// Appear in the timings track (they still appear in the main thread\n// flame chart).\nconst ignoredNames = [...resourceTimingNames, ...navTimingNames];\n\nfunction getEventTimings(event: Types.Events.SyntheticEventPair|Types.Events.ConsoleTimeStamp):\n {start: Types.Timing.Micro, end: Types.Timing.Micro} {\n if ('dur' in event) {\n // It's a SyntheticEventPair.\n return {start: event.ts, end: Types.Timing.Micro(event.ts + (event.dur ?? 0))};\n }\n\n if (Types.Events.isConsoleTimeStamp(event)) {\n const {start, end} = event.args.data || {};\n if (typeof start === 'number' && typeof end === 'number') {\n return {start: Types.Timing.Micro(start), end: Types.Timing.Micro(end)};\n }\n }\n\n // A ConsoleTimeStamp without start/end is just a point in time, so dur is 0.\n return {start: event.ts, end: event.ts};\n}\n\nfunction getEventTrack(event: Types.Events.SyntheticEventPair|Types.Events.ConsoleTimeStamp): string|undefined {\n if (event.cat === 'blink.user_timing') {\n // This is a SyntheticUserTimingPair\n const detailString =\n ((event as Types.Events.SyntheticUserTimingPair).args.data.beginEvent.args as {detail?: string})?.detail;\n if (detailString) {\n const details = Helpers.Trace.parseDevtoolsDetails(detailString, 'devtools');\n if (details && 'track' in details) {\n return details.track;\n }\n }\n } else if (Types.Events.isConsoleTimeStamp(event)) {\n const track = event.args.data?.track;\n return typeof track === 'string' ? track : undefined;\n }\n\n // SyntheticConsoleTimingPair does not have track info.\n return undefined;\n}\n\n/**\n * Similar to the default {@see Helpers.Trace.eventTimeComparator}\n * but with a twist:\n * In case of equal start and end times, put the second event (within a\n * track) first.\n *\n * Explanation:\n * User timing entries come as trace events dispatched when\n * performance.measure/mark is called. The trace events buffered in\n * devtools frontend are sorted by the start time. If their start time\n * is the same, then the event for the first call will appear first.\n *\n * When entries are meant to be stacked, the corresponding\n * performance.measure calls usually are done in bottom-up direction:\n * calls for children first and for parent later (because the call\n * is usually done when the measured task is over). This means that\n * when two user timing events have the same start and end time, usually\n * the second event is the parent of the first. Hence the switch.\n *\n */\nexport function userTimingComparator<T extends Types.Events.SyntheticEventPair|Types.Events.ConsoleTimeStamp>(\n a: T, b: T, originalArray: readonly T[]): number {\n const {start: aStart, end: aEnd} = getEventTimings(a);\n const {start: bStart, end: bEnd} = getEventTimings(b);\n const timeDifference = Helpers.Trace.compareBeginAndEnd(aStart, bStart, aEnd, bEnd);\n if (timeDifference) {\n return timeDifference;\n }\n\n // Never re-order entries across different tracks.\n const aTrack = getEventTrack(a);\n const bTrack = getEventTrack(b);\n if (aTrack !== bTrack) {\n return 0; // Preserve current positions.\n }\n\n // Prefer the event located in a further position in the original array.\n const aIndex = originalArray.indexOf(a);\n const bIndex = originalArray.indexOf(b);\n return bIndex - aIndex;\n}\n\nexport function handleEvent(event: Types.Events.Event): void {\n if (ignoredNames.includes(event.name)) {\n return;\n }\n if (Types.Events.isUserTimingMeasure(event)) {\n measureTraceByTraceId.set(event.args.traceId, event);\n }\n if (Types.Events.isPerformanceMeasure(event)) {\n performanceMeasureEvents.push(event);\n return;\n }\n if (Types.Events.isPerformanceMark(event)) {\n performanceMarkEvents.push(event);\n }\n if (Types.Events.isConsoleTime(event)) {\n consoleTimings.push(event);\n }\n if (Types.Events.isConsoleTimeStamp(event)) {\n timestampEvents.push(event);\n }\n}\n\nexport async function finalize(): Promise<void> {\n const asyncEvents = [...performanceMeasureEvents, ...consoleTimings];\n syntheticEvents = Helpers.Trace.createMatchedSortedSyntheticEvents(asyncEvents);\n syntheticEvents = syntheticEvents.sort((a, b) => userTimingComparator(a, b, [...syntheticEvents]));\n timestampEvents = timestampEvents.sort((a, b) => userTimingComparator(a, b, [...timestampEvents]));\n}\n\nexport function data(): UserTimingsData {\n return {\n consoleTimings: syntheticEvents.filter(e => e.cat === 'blink.console') as Types.Events.SyntheticConsoleTimingPair[],\n performanceMeasures: syntheticEvents.filter(e => e.cat === 'blink.user_timing') as\n Types.Events.SyntheticUserTimingPair[],\n performanceMarks: performanceMarkEvents,\n timestampEvents,\n measureTraceByTraceId,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"UserTimingsHandler.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/handlers/UserTimingsHandler.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2022 The Chromium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\n/**\n * IMPORTANT!\n * See UserTimings.md in this directory for some handy documentation on\n * UserTimings and the trace events we parse currently.\n **/\nlet syntheticEvents: Array<Types.Events.SyntheticEventPair<Types.Events.PairableAsync>> = [];\n\n// There are two events dispatched for performance.measure calls: one to\n// represent the measured timing in the tracing clock (which we type as\n// PerformanceMeasure) and another one for the call itself (which we\n// type as UserTimingMeasure). The two events corresponding to the same\n// call are linked together by a common trace_id. The reason two events\n// are dispatched is because the first was originally added with the\n// implementation of the performance.measure API and it uses an\n// overridden timestamp and duration. To prevent breaking potential deps\n// created since then, a second event was added instead of changing the\n// params of the first.\nlet measureTraceByTraceId = new Map<number, Types.Events.UserTimingMeasure>();\nlet performanceMeasureEvents: Types.Events.PerformanceMeasure[] = [];\nlet performanceMarkEvents: Types.Events.PerformanceMark[] = [];\n\nlet consoleTimings: Array<Types.Events.ConsoleTimeBegin|Types.Events.ConsoleTimeEnd> = [];\n\nlet timestampEvents: Types.Events.ConsoleTimeStamp[] = [];\n\nexport interface UserTimingsData {\n /**\n * Events triggered with the performance.measure() API.\n * https://developer.mozilla.org/en-US/docs/Web/API/Performance/measure\n */\n performanceMeasures: readonly Types.Events.SyntheticUserTimingPair[];\n /**\n * Events triggered with the performance.mark() API.\n * https://developer.mozilla.org/en-US/docs/Web/API/Performance/mark\n */\n performanceMarks: readonly Types.Events.PerformanceMark[];\n /**\n * Events triggered with the console.time(), console.timeEnd() and\n * console.timeLog() API.\n * https://developer.mozilla.org/en-US/docs/Web/API/console/time\n */\n consoleTimings: readonly Types.Events.SyntheticConsoleTimingPair[];\n /**\n * Events triggered with the console.timeStamp() API\n * https://developer.mozilla.org/en-US/docs/Web/API/console/timeStamp\n */\n timestampEvents: readonly Types.Events.ConsoleTimeStamp[];\n /**\n * Events triggered to trace the call to performance.measure itself,\n * cached by trace_id.\n */\n measureTraceByTraceId: Map<number, Types.Events.UserTimingMeasure>;\n}\n\nexport function reset(): void {\n syntheticEvents = [];\n performanceMeasureEvents = [];\n performanceMarkEvents = [];\n consoleTimings = [];\n timestampEvents = [];\n measureTraceByTraceId = new Map();\n}\n\nconst resourceTimingNames = [\n 'workerStart',\n 'redirectStart',\n 'redirectEnd',\n 'fetchStart',\n 'domainLookupStart',\n 'domainLookupEnd',\n 'connectStart',\n 'connectEnd',\n 'secureConnectionStart',\n 'requestStart',\n 'responseStart',\n 'responseEnd',\n];\nconst navTimingNames = [\n 'navigationStart',\n 'unloadEventStart',\n 'unloadEventEnd',\n 'redirectStart',\n 'redirectEnd',\n 'fetchStart',\n 'commitNavigationEnd',\n 'domainLookupStart',\n 'domainLookupEnd',\n 'connectStart',\n 'connectEnd',\n 'secureConnectionStart',\n 'requestStart',\n 'responseStart',\n 'responseEnd',\n 'domLoading',\n 'domInteractive',\n 'domContentLoadedEventStart',\n 'domContentLoadedEventEnd',\n 'domComplete',\n 'loadEventStart',\n 'loadEventEnd',\n];\n// These are events dispatched under the blink.user_timing category\n// but that the user didn't add. Filter them out so that they do not\n// Appear in the timings track (they still appear in the main thread\n// flame chart).\nconst ignoredNames = [...resourceTimingNames, ...navTimingNames];\n\nfunction getEventTimings(event: Types.Events.SyntheticEventPair|Types.Events.ConsoleTimeStamp):\n {start: Types.Timing.Micro, end: Types.Timing.Micro} {\n if ('dur' in event) {\n // It's a SyntheticEventPair.\n return {start: event.ts, end: Types.Timing.Micro(event.ts + (event.dur ?? 0))};\n }\n\n if (Types.Events.isConsoleTimeStamp(event)) {\n const {start, end} = event.args.data || {};\n if (typeof start === 'number' && typeof end === 'number') {\n return {start: Types.Timing.Micro(start), end: Types.Timing.Micro(end)};\n }\n }\n\n // A ConsoleTimeStamp without start/end is just a point in time, so dur is 0.\n return {start: event.ts, end: event.ts};\n}\n\nfunction getEventTrack(event: Types.Events.SyntheticEventPair|Types.Events.ConsoleTimeStamp): string|undefined {\n if (event.cat === 'blink.user_timing') {\n // This is a SyntheticUserTimingPair\n const detailString =\n ((event as Types.Events.SyntheticUserTimingPair).args.data.beginEvent.args as {detail?: string})?.detail;\n if (detailString) {\n const details = Helpers.Trace.parseDevtoolsDetails(detailString, 'devtools');\n if (details && 'track' in details) {\n return details.track;\n }\n }\n } else if (Types.Events.isConsoleTimeStamp(event)) {\n const track = event.args.data?.track;\n return typeof track === 'string' ? track : undefined;\n }\n\n // SyntheticConsoleTimingPair does not have track info.\n return undefined;\n}\n\n/**\n * Similar to the default {@link Helpers.Trace.eventTimeComparator}\n * but with a twist:\n * In case of equal start and end times, put the second event (within a\n * track) first.\n *\n * Explanation:\n * User timing entries come as trace events dispatched when\n * performance.measure/mark is called. The trace events buffered in\n * devtools frontend are sorted by the start time. If their start time\n * is the same, then the event for the first call will appear first.\n *\n * When entries are meant to be stacked, the corresponding\n * performance.measure calls usually are done in bottom-up direction:\n * calls for children first and for parent later (because the call\n * is usually done when the measured task is over). This means that\n * when two user timing events have the same start and end time, usually\n * the second event is the parent of the first. Hence the switch.\n *\n */\nexport function userTimingComparator<T extends Types.Events.SyntheticEventPair|Types.Events.ConsoleTimeStamp>(\n a: T, b: T, originalArray: readonly T[]): number {\n const {start: aStart, end: aEnd} = getEventTimings(a);\n const {start: bStart, end: bEnd} = getEventTimings(b);\n const timeDifference = Helpers.Trace.compareBeginAndEnd(aStart, bStart, aEnd, bEnd);\n if (timeDifference) {\n return timeDifference;\n }\n\n // Never re-order entries across different tracks.\n const aTrack = getEventTrack(a);\n const bTrack = getEventTrack(b);\n if (aTrack !== bTrack) {\n return 0; // Preserve current positions.\n }\n\n // Prefer the event located in a further position in the original array.\n const aIndex = originalArray.indexOf(a);\n const bIndex = originalArray.indexOf(b);\n return bIndex - aIndex;\n}\n\nexport function handleEvent(event: Types.Events.Event): void {\n if (ignoredNames.includes(event.name)) {\n return;\n }\n if (Types.Events.isUserTimingMeasure(event)) {\n measureTraceByTraceId.set(event.args.traceId, event);\n }\n if (Types.Events.isPerformanceMeasure(event)) {\n performanceMeasureEvents.push(event);\n return;\n }\n if (Types.Events.isPerformanceMark(event)) {\n performanceMarkEvents.push(event);\n }\n if (Types.Events.isConsoleTime(event)) {\n consoleTimings.push(event);\n }\n if (Types.Events.isConsoleTimeStamp(event)) {\n timestampEvents.push(event);\n }\n}\n\nexport async function finalize(): Promise<void> {\n const asyncEvents = [...performanceMeasureEvents, ...consoleTimings];\n syntheticEvents = Helpers.Trace.createMatchedSortedSyntheticEvents(asyncEvents);\n syntheticEvents = syntheticEvents.sort((a, b) => userTimingComparator(a, b, [...syntheticEvents]));\n timestampEvents = timestampEvents.sort((a, b) => userTimingComparator(a, b, [...timestampEvents]));\n}\n\nexport function data(): UserTimingsData {\n return {\n consoleTimings: syntheticEvents.filter(e => e.cat === 'blink.console') as Types.Events.SyntheticConsoleTimingPair[],\n performanceMeasures: syntheticEvents.filter(e => e.cat === 'blink.user_timing') as\n Types.Events.SyntheticUserTimingPair[],\n performanceMarks: performanceMarkEvents,\n timestampEvents,\n measureTraceByTraceId,\n };\n}\n"]}
|
|
@@ -10,7 +10,7 @@ export declare const UIStrings: {
|
|
|
10
10
|
* @description Description of a DevTools insight that identifies the reasons that elements shift on the page.
|
|
11
11
|
* This is displayed after a user expands the section to see more. No character length limits.
|
|
12
12
|
*/
|
|
13
|
-
readonly description: "Layout shifts occur when elements move absent any user interaction. [Investigate the causes of layout shifts](https://
|
|
13
|
+
readonly description: "Layout shifts occur when elements move absent any user interaction. [Investigate the causes of layout shifts](https://developer.chrome.com/docs/performance/insights/cls-culprit), such as elements being added, removed, or their fonts changing as the page loads.";
|
|
14
14
|
/**
|
|
15
15
|
* @description Text indicating the worst layout shift cluster.
|
|
16
16
|
*/
|
|
@@ -14,7 +14,7 @@ export const UIStrings = {
|
|
|
14
14
|
* @description Description of a DevTools insight that identifies the reasons that elements shift on the page.
|
|
15
15
|
* This is displayed after a user expands the section to see more. No character length limits.
|
|
16
16
|
*/
|
|
17
|
-
description: 'Layout shifts occur when elements move absent any user interaction. [Investigate the causes of layout shifts](https://
|
|
17
|
+
description: 'Layout shifts occur when elements move absent any user interaction. [Investigate the causes of layout shifts](https://developer.chrome.com/docs/performance/insights/cls-culprit), such as elements being added, removed, or their fonts changing as the page loads.',
|
|
18
18
|
/**
|
|
19
19
|
* @description Text indicating the worst layout shift cluster.
|
|
20
20
|
*/
|
|
@@ -445,6 +445,7 @@ function finalize(partialModel) {
|
|
|
445
445
|
strings: UIStrings,
|
|
446
446
|
title: i18nString(UIStrings.title),
|
|
447
447
|
description: i18nString(UIStrings.description),
|
|
448
|
+
docs: 'https://developer.chrome.com/docs/performance/insights/cls-culprit',
|
|
448
449
|
category: InsightCategory.CLS,
|
|
449
450
|
state,
|
|
450
451
|
...partialModel,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CLSCulprits.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/CLSCulprits.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,IAAI,MAAM,4BAA4B,CAAC;AACnD,OAAO,KAAK,QAAQ,MAAM,oCAAoC,CAAC;AAE/D,OAAO,KAAK,QAAQ,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AACjD,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAC;AAE3C,OAAO,EACL,eAAe,EACf,WAAW,GAIZ,MAAM,YAAY,CAAC;AAEpB,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,gKAAgK;IAChK,KAAK,EAAE,uBAAuB;IAC9B;;;OAGG;IACH,WAAW,EACP,yOAAyO;IAC7O;;OAEG;IACH,uBAAuB,EAAE,4BAA4B;IACrD;;OAEG;IACH,YAAY,EAAE,eAAe;IAC7B;;;OAGG;IACH,kBAAkB,EAAE,8BAA8B;IAClD;;OAEG;IACH,WAAW,EAAE,2BAA2B;IACxC;;OAEG;IACH,cAAc,EAAE,iBAAiB;IACjC;;OAEG;IACH,OAAO,EAAE,UAAU;IACnB;;OAEG;IACH,SAAS,EAAE,WAAW;IACtB;;OAEG;IACH,YAAY,EAAE,uBAAuB;IACrC;;OAEG;IACH,cAAc,EAAE,kBAAkB;IAClC;;OAEG;IACH,UAAU,EAAE,4CAA4C;CAChD,CAAC;AAEX,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,sCAAsC,EAAE,SAAS,CAAC,CAAC;AAC5F,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAW7E,MAAM,CAAN,IAAY,uBAoBX;AApBD,WAAY,uBAAuB;IACjC,8FAAmE,CAAA;IACnE,0FAA+D,CAAA;IAC/D,sFAA2D,CAAA;IAC3D,wGAA6E,CAAA;IAC7E,0GAA+E,CAAA;IAC/E,wGAA6E,CAAA;IAC7E,oGAAyE,CAAA;IACzE,0EAA+C,CAAA;IAC/C,wGAA6E,CAAA;IAC7E,oJACgE,CAAA;IAChE,wFAA6D,CAAA;IAC7D,8GAAmF,CAAA;IACnF,gFAAqD,CAAA;IACrD,oFAAyD,CAAA;IACzD,0HAA+F,CAAA;IAC/F,8FAAmE,CAAA;IACnE,oFAAyD,CAAA;IACzD,0HAA+F,CAAA;AACjG,CAAC,EApBW,uBAAuB,KAAvB,uBAAuB,QAoBlC;AAED,MAAM,CAAN,IAAY,eAKX;AALD,WAAY,eAAe;IACzB,6DAAY,CAAA;IACZ,2DAAW,CAAA;IACX,iEAAc,CAAA;IACd,uEAAiB,CAAA;AACnB,CAAC,EALW,eAAe,KAAf,eAAe,QAK1B;AAiCD;;;;GAIG;AACH,MAAM,0BAA0B,GAI5B;IACE;QACE,IAAI,EAAE,CAAC,IAAI,CAAC;QACZ,OAAO,EAAE,uBAAuB,CAAC,+BAA+B;KACjE;IACD;QACE,IAAI,EAAE,CAAC,IAAI,CAAC;QACZ,OAAO,EAAE,uBAAuB,CAAC,6BAA6B;KAC/D;IACD;QACE,IAAI,EAAE,CAAC,IAAI,CAAC;QACZ,OAAO,EAAE,uBAAuB,CAAC,2BAA2B;KAC7D;IACD;QACE,IAAI,EAAE,CAAC,IAAI,CAAC;QACZ,OAAO,EAAE,uBAAuB,CAAC,oCAAoC;KACtE;IACD;QACE,IAAI,EAAE,CAAC,IAAI,CAAC;QACZ,OAAO,EAAE,uBAAuB,CAAC,qCAAqC;KACvE;IACD;QACE,IAAI,EAAE,CAAC,IAAI,CAAC;QACZ,OAAO,EAAE,uBAAuB,CAAC,oCAAoC;KACtE;IACD;QACE,IAAI,EAAE,CAAC,IAAI,CAAC;QACZ,OAAO,EAAE,uBAAuB,CAAC,kCAAkC;KACpE;IACD;QACE,IAAI,EAAE,CAAC,IAAI,CAAC;QACZ,OAAO,EAAE,uBAAuB,CAAC,qBAAqB;KACvD;IACD,oDAAoD;IACpD;QACE,IAAI,EAAE,CAAC,IAAI,CAAC;QACZ,OAAO,EAAE,uBAAuB,CAAC,oCAAoC;KACtE;IACD;QACE,IAAI,EAAE,CAAC,IAAI,EAAE;QACb,OAAO,EAAE,uBAAuB,CAAC,0DAA0D;KAC5F;IACD;QACE,IAAI,EAAE,CAAC,IAAI,EAAE;QACb,OAAO,EAAE,uBAAuB,CAAC,4BAA4B;KAC9D;IACD;QACE,IAAI,EAAE,CAAC,IAAI,EAAE;QACb,OAAO,EAAE,uBAAuB,CAAC,uCAAuC;KACzE;IACD;QACE,IAAI,EAAE,CAAC,IAAI,EAAE;QACb,OAAO,EAAE,uBAAuB,CAAC,wBAAwB;KAC1D;IACD,qDAAqD;IACrD;QACE,IAAI,EAAE,CAAC,IAAI,EAAE;QACb,OAAO,EAAE,uBAAuB,CAAC,0BAA0B;KAC5D;IACD;QACE,IAAI,EAAE,CAAC,IAAI,EAAE;QACb,OAAO,EAAE,uBAAuB,CAAC,6CAA6C;KAC/E;IACD;QACE,IAAI,EAAE,CAAC,IAAI,EAAE;QACb,OAAO,EAAE,uBAAuB,CAAC,+BAA+B;KACjE;IACD;QACE,IAAI,EAAE,CAAC,IAAI,EAAE;QACb,OAAO,EAAE,uBAAuB,CAAC,0BAA0B;KAC5D;IACD;QACE,IAAI,EAAE,CAAC,IAAI,EAAE;QACb,OAAO,EAAE,uBAAuB,CAAC,6CAA6C;KAC/E;CACO,CAAC;AAEf,gBAAgB;AAChB,uFAAuF;AACvF,MAAM,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;AAmBnF;;;;GAIG;AACH,SAAS,mBAAmB,CAAC,KAAyB,EAAE,WAA+B;IACrF,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;IAC7D,OAAO,QAAQ,GAAG,WAAW,CAAC,EAAE,IAAI,QAAQ,IAAI,WAAW,CAAC,EAAE,GAAG,iBAAiB,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,cAAmD;IAEzF,MAAM,QAAQ,GAAoC,EAAE,CAAC;IACrD,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;IACvD,MAAM,aAAa,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,EAAE,CAAC;IACnE;;;OAGG;IACH,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;QAClC,MAAM,WAAW,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC;QACpD,MAAM,qBAAqB,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC;QACpE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,SAAS;QACX,CAAC;QACD,MAAM,cAAc,GAChB,0BAA0B,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACzG,MAAM,OAAO,GAAkC;YAC7C,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW;YACtC,cAAc;YACd,qBAAqB;YACrB,SAAS,EAAE,cAAc;SAC1B,CAAC;QACF,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,iCAAiC,CACtC,eAAsD,EACtD,cAAuC,EACvC,gBAAiF,EACjF,iBAAoF;IAEtF,MAAM,oBAAoB,GAAoC,EAAE,CAAC;IACjE,KAAK,MAAM,SAAS,IAAI,eAAe,EAAE,CAAC;QACxC;;;WAGG;QACH,MAAM,QAAQ,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC;QACpD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,SAAS;QACX,CAAC;QACD,oBAAoB,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;QAEvC,MAAM,YAAY,GAAG,YAAY,CAAC,cAAc,EAAE,SAAS,CAAiC,CAAC;QAC7F,sDAAsD;QACtD,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,SAAS;QACX,CAAC;QAED,yFAAyF;QACzF,IAAI,CAAC,mBAAmB,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE,CAAC;YAClD,SAAS;QACX,CAAC;QAED,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAClD,mDAAmD;QACnD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,SAAS;QACX,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACxD,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;YACvC,CAAC;YACD,kBAAkB,CAAC,uBAAuB,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IAED,OAAO,oBAAoB,CAAC;AAC9B,CAAC;AAED;;;GAGG;AACH,SAAS,yBAAyB,CAC9B,YAAiD,EACjD,cAAuC;IAEzC,uEAAuE;IACvE,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAA8D,CAAC;IAE/F,wDAAwD;IACxD,KAAK,MAAM,aAAa,IAAI,cAAc,EAAE,CAAC;QAC3C,MAAM,eAAe,GACjB,QAAQ,CAAC,cAAc,CAAC,yBAAyB,CAAC,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,IAAI,aAAa,CAAC,EAAE,CAAC,CAAC;QAC3G,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;YAC7B,mEAAmE;YACnE,SAAS;QACX,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,eAAe,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3D,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;YAC9B,IAAI,KAAK,CAAC,EAAE,IAAI,aAAa,CAAC,EAAE,IAAI,KAAK,CAAC,EAAE,IAAI,aAAa,CAAC,EAAE,GAAG,aAAa,CAAC,GAAG,EAAE,CAAC;gBACrF,MAAM,gBAAgB,GAAG,QAAQ,CAAC,YAAY,CAAC,cAAc,CAAC,gBAAgB,EAAE,aAAa,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;gBACzG,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC/B,CAAC;YACD,IAAI,KAAK,CAAC,EAAE,GAAG,aAAa,CAAC,EAAE,GAAG,aAAa,CAAC,GAAG,EAAE,CAAC;gBACpD,iGAAiG;gBACjG,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,YAAkC,EAAE,WAA+B;IAEvF,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAC,yBAAyB,CAC3D,YAAY,EAAE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,WAAW,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACjF,gDAAgD;IAChD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CACxB,IAAgC,EAAE,mBAA4E,EAC9G,cAAuC,EACvC,gBAAiF,EACjF,iBAAoF,EACpF,gBAAoD;IAEtD,KAAK,MAAM,WAAW,IAAI,mBAAmB,EAAE,CAAC;QAC9C,MAAM,YAAY,GAAG,YAAY,CAAC,cAAc,EAAE,WAAW,CAAiC,CAAC;QAC/F,sDAAsD;QACtD,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAClD,mDAAmD;QACnD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,SAAS;QACX,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACxD,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;YACvC,CAAC;YAED,kFAAkF;YAClF,8BAA8B;YAC9B,MAAM,QAAQ,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;gBACzC,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;gBAC9E,OAAO,CAAC,CAAC,EAAE,IAAI,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,SAAS,CAAC;YACrD,CAAC,CAAC,CAAC;YACH,IAAI,QAAQ,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;gBACzB,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;gBAElC,IAAI,GAAG,CAAC;gBACR,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBAChE,IAAI,SAAS,IAAI,SAAS,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;oBACpC,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;gBAClD,CAAC;gBAED,kBAAkB,CAAC,OAAO,CAAC,IAAI,CAAC,EAAC,KAAK,EAAE,GAAG,EAAC,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,yBAAyB,CAC9B,kBAA8D,EAAE,gBAA2C,EAC3G,gBAAiF,EACjF,iBAAoF;IAEtF,gBAAgB,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE;QAC5C,MAAM,UAAU,GAAG,YAAY,CAAC,gBAAgB,EAAE,QAAQ,CAAmC,CAAC;QAC9F,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO;QACT,CAAC;QACD,oDAAoD;QACpD,MAAM,YAAY,GACd,kBAAkB,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3G,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAO;QACT,CAAC;QACD,kFAAkF;QAClF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACxD,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;YACvC,CAAC;YACD,kBAAkB,CAAC,aAAa,CAAC,IAAI,CAAC;gBACpC,aAAa,EAAE,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;gBAC5C,eAAe,EAAE,UAAU;aAC5B,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;IACH,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAAqB;IACxD,OAAO,OAAO,CAAC,UAAU,KAAK,WAAW,CAAC,YAAY,CAAC;AACzD,CAAC;AAED;;;;GAIG;AACH,SAAS,iBAAiB,CACtB,eAAuD,EAAE,cAAuC,EAChG,gBAAiF,EACjF,iBAAoF;IAEtF,MAAM,YAAY,GACd,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,KAAK,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IAEtH,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,MAAM,YAAY,GAAG,YAAY,CAAC,cAAc,EAAE,GAAG,CAAiC,CAAC;QACvF,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,SAAS;QACX,CAAC;QAED,6EAA6E;QAC7E,IAAI,CAAC,mBAAmB,CAAC,GAAG,EAAE,YAAY,CAAC,EAAE,CAAC;YAC5C,SAAS;QACX,CAAC;QAED,8CAA8C;QAC9C,MAAM,MAAM,GAAG,gBAAgB,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAElD,2EAA2E;QAC3E,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,SAAS;QACX,CAAC;QACD,yDAAyD;QACzD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACxD,IAAI,CAAC,kBAAkB,EAAE,CAAC;gBACxB,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;YACvC,CAAC;YACD,kBAAkB,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IACD,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CACnB,OAAiD,EACjD,eAAkF;IACpF,MAAM,gBAAgB,GAAG,CAAC,CAAC;IAC3B,MAAM,MAAM,GAAsB,EAAE,CAAC;IAErC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC5C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC;QAClC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;QACjC,MAAM,UAAU,GAAG,QAAQ,CAAC,uBAAuB,CAAC;QACpD,MAAM,aAAa,GAAG,QAAQ,CAAC,aAAa,CAAC;QAE7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5E,MAAM,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,eAAe,CAAC,QAAQ,EAAE,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,EAAC,CAAC,CAAC;QAC5F,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5E,MAAM,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,eAAe,CAAC,OAAO,EAAE,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,cAAc,CAAC,EAAC,CAAC,CAAC;QAClG,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/E,MAAM,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,eAAe,CAAC,UAAU,EAAE,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,SAAS,CAAC,EAAC,CAAC,CAAC;QAChG,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC,EAAE,EAAE,CAAC;YAClF,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,eAAe,CAAC,aAAa;gBACnC,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,YAAY,CAAC;gBAC/C,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE;gBACzD,aAAa,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,aAAa;gBAC7C,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;aAC9D,CAAC,CAAC;QACL,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,IAAI,gBAAgB,EAAE,CAAC;YACtC,MAAM;QACR,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,QAAQ,CAAC,YAA0D;IAC1E,IAAI,KAAK,GAAqC,MAAM,CAAC;IACrD,IAAI,YAAY,CAAC,YAAY,EAAE,CAAC;QAC9B,MAAM,cAAc,GAAG,QAAQ,CAAC,aAAa,CAAC,YAAY,CAAC,iCAAiC,CACxF,YAAY,CAAC,YAAY,CAAC,sBAAsB,CAAC,CAAC;QACtD,IAAI,cAAc,KAAK,QAAQ,CAAC,aAAa,CAAC,eAAe,CAAC,mBAAmB,CAAC,IAAI,EAAE,CAAC;YACvF,KAAK,GAAG,aAAa,CAAC;QACxB,CAAC;aAAM,CAAC;YACN,KAAK,GAAG,MAAM,CAAC;QACjB,CAAC;IACH,CAAC;IAED,OAAO;QACL,UAAU,EAAE,WAAW,CAAC,YAAY;QACpC,OAAO,EAAE,SAAS;QAClB,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC;QAClC,WAAW,EAAE,UAAU,CAAC,SAAS,CAAC,WAAW,CAAC;QAC9C,QAAQ,EAAE,eAAe,CAAC,GAAG;QAC7B,KAAK;QACL,GAAG,YAAY;KAChB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAgC,EAAE,OAA0B;IAC1F,MAAM,eAAe,GAAG,CAAC,KAAyB,EAAW,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAEtH,MAAM,wBAAwB,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IACpF,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC,qCAAqC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IACrG,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAC5E,MAAM,gBAAgB,GAAG,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IACpF,MAAM,kBAAkB,GAAG,IAAI,CAAC,YAAY,CAAC,wBAAwB,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAE9F,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC;IAC1F,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,sBAAsB,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IAChF,MAAM,eAAe,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,sBAAsB,GAAG,CAAC,CAAC,sBAAsB,CAAC,CAAC;IAC1G,MAAM,YAAY,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3C,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjE,MAAM,cAAc,GAAG,IAAI,CAAC,YAAY,CAAC,cAAc,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAChF,MAAM,gBAAgB,GAAG,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAEpF,mBAAmB;IACnB,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAgE,CAAC;IAClG,MAAM,gBAAgB,GAAG,yBAAyB,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;IAEjF,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,iBAAiB,CAAC,GAAG,CAAC,KAAK,EAAE,EAAC,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,uBAAuB,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAC,CAAC,CAAC;IAC5G,CAAC;IAED,8CAA8C;IAC9C,mBAAmB,CAAC,IAAI,EAAE,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,CAAC,CAAC;IAC/G,iBAAiB,CAAC,eAAe,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,CAAC,CAAC;IACxF,yBAAyB,CAAC,kBAAkB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,iBAAiB,CAAC,CAAC;IACrG,MAAM,iBAAiB,GACnB,iCAAiC,CAAC,wBAAwB,EAAE,cAAc,EAAE,gBAAgB,EAAE,iBAAiB,CAAC,CAAC;IAErH,MAAM,aAAa,GAAyB,CAAC,GAAG,YAAY,CAAC,CAAC;IAC9D,IAAI,YAAY,EAAE,CAAC;QACjB,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IACnC,CAAC;IAED,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAA+D,CAAC;IACpG,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,oBAAoB,CAAC,GAAG,CAAC,OAAO,EAAE,cAAc,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAChF,CAAC;IAED,OAAO,QAAQ,CAAC;QACd,aAAa;QACb,iBAAiB;QACjB,MAAM,EAAE,iBAAiB;QACzB,QAAQ;QACR,YAAY;QACZ,oBAAoB;KACrB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAA8B;IAC3D,MAAM,eAAe,GAAG,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,sBAAsB,GAAG,CAAC,CAAC,sBAAsB,CAAC,IAAI,EAAE,CAAC;IACrH,MAAM,YAAY,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;IACxC,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IACxD,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC;IAExD,OAAO,CAAC;YACN,IAAI,EAAE,oBAAoB;YAC1B,QAAQ,EAAE;gBACR;oBACE,MAAM,EAAE,EAAC,GAAG,EAAE,YAAY,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,EAAC;oBAC1C,KAAK,EAAE,UAAU,CAAC,SAAS,CAAC,uBAAuB,CAAC;oBACpD,YAAY,EAAE,KAAK;iBACpB;aACF;YACD,4DAA4D;YAC5D,KAAK,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;YAC7B,cAAc,EAAE,aAAa;SAC9B,CAAC,CAAC;AACL,CAAC","sourcesContent":["// Copyright 2024 The Chromium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Platform from '../../../core/platform/platform.js';\nimport type * as Protocol from '../../../generated/protocol.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /** Title of an insight that provides details about why elements shift/move on the page. The causes for these shifts are referred to as culprits (\"reasons\"). */\n title: 'Layout shift culprits',\n /**\n * @description Description of a DevTools insight that identifies the reasons that elements shift on the page.\n * This is displayed after a user expands the section to see more. No character length limits.\n */\n description:\n 'Layout shifts occur when elements move absent any user interaction. [Investigate the causes of layout shifts](https://web.dev/articles/optimize-cls), such as elements being added, removed, or their fonts changing as the page loads.',\n /**\n * @description Text indicating the worst layout shift cluster.\n */\n worstLayoutShiftCluster: 'Worst layout shift cluster',\n /**\n * @description Text indicating the worst layout shift cluster.\n */\n worstCluster: 'Worst cluster',\n /**\n * @description Text indicating a layout shift cluster and its start time.\n * @example {32 ms} PH1\n */\n layoutShiftCluster: 'Layout shift cluster @ {PH1}',\n /**\n * @description Text indicating the biggest reasons for the layout shifts.\n */\n topCulprits: 'Top layout shift culprits',\n /**\n * @description Text for a culprit type of Injected iframe.\n */\n injectedIframe: 'Injected iframe',\n /**\n * @description Text for a culprit type of web font request.\n */\n webFont: 'Web font',\n /**\n * @description Text for a culprit type of Animation.\n */\n animation: 'Animation',\n /**\n * @description Text for a culprit type of Unsized image.\n */\n unsizedImage: 'Unsized image element',\n /**\n * @description Text status when there were no layout shifts detected.\n */\n noLayoutShifts: 'No layout shifts',\n /**\n * @description Text status when there no layout shifts culprits/root causes were found.\n */\n noCulprits: 'Could not detect any layout shift culprits',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/CLSCulprits.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type CLSCulpritsInsightModel = InsightModel<typeof UIStrings, {\n animationFailures: readonly NoncompositedAnimationFailure[],\n shifts: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>,\n clusters: Types.Events.SyntheticLayoutShiftCluster[],\n worstCluster: Types.Events.SyntheticLayoutShiftCluster | undefined,\n /** The top 3 shift root causes for each cluster. */\n topCulpritsByCluster: Map<Types.Events.SyntheticLayoutShiftCluster, LayoutShiftItem[]>,\n}>;\n\nexport enum AnimationFailureReasons {\n ACCELERATED_ANIMATIONS_DISABLED = 'ACCELERATED_ANIMATIONS_DISABLED',\n EFFECT_SUPPRESSED_BY_DEVTOOLS = 'EFFECT_SUPPRESSED_BY_DEVTOOLS',\n INVALID_ANIMATION_OR_EFFECT = 'INVALID_ANIMATION_OR_EFFECT',\n EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS = 'EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS',\n EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE = 'EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE',\n TARGET_HAS_INVALID_COMPOSITING_STATE = 'TARGET_HAS_INVALID_COMPOSITING_STATE',\n TARGET_HAS_INCOMPATIBLE_ANIMATIONS = 'TARGET_HAS_INCOMPATIBLE_ANIMATIONS',\n TARGET_HAS_CSS_OFFSET = 'TARGET_HAS_CSS_OFFSET',\n ANIMATION_AFFECTS_NON_CSS_PROPERTIES = 'ANIMATION_AFFECTS_NON_CSS_PROPERTIES',\n TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET =\n 'TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET',\n TRANSFROM_BOX_SIZE_DEPENDENT = 'TRANSFROM_BOX_SIZE_DEPENDENT',\n FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS = 'FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS',\n UNSUPPORTED_CSS_PROPERTY = 'UNSUPPORTED_CSS_PROPERTY',\n MIXED_KEYFRAME_VALUE_TYPES = 'MIXED_KEYFRAME_VALUE_TYPES',\n TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE = 'TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE',\n ANIMATION_HAS_NO_VISIBLE_CHANGE = 'ANIMATION_HAS_NO_VISIBLE_CHANGE',\n AFFECTS_IMPORTANT_PROPERTY = 'AFFECTS_IMPORTANT_PROPERTY',\n SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY = 'SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY',\n}\n\nexport enum LayoutShiftType {\n WEB_FONT = 0,\n IFRAMES = 1,\n ANIMATIONS = 2,\n UNSIZED_IMAGE = 3,\n}\n\nexport type LayoutShiftItem = {\n type: LayoutShiftType.UNSIZED_IMAGE,\n description: Platform.UIString.LocalizedString,\n url: string,\n backendNodeId: Protocol.DOM.BackendNodeId,\n frame: string,\n}|{\n type: Exclude<LayoutShiftType, LayoutShiftType.UNSIZED_IMAGE>,\n description: Platform.UIString.LocalizedString,\n};\n\nexport interface NoncompositedAnimationFailure {\n /**\n * Animation name.\n */\n name?: string;\n /**\n * Failure reason based on mask number defined in\n * https://source.chromium.org/search?q=f:compositor_animations.h%20%22enum%20FailureReason%22.\n */\n failureReasons: AnimationFailureReasons[];\n /**\n * Unsupported properties.\n */\n unsupportedProperties?: Types.Events.Animation['args']['data']['unsupportedProperties'];\n /**\n * Animation event.\n */\n animation?: Types.Events.SyntheticAnimationPair;\n}\n\n/**\n * Each failure reason is represented by a bit flag. The bit shift operator '<<' is used to define\n * which bit corresponds to each failure reason.\n * https://source.chromium.org/search?q=f:compositor_animations.h%20%22enum%20FailureReason%22\n */\nconst ACTIONABLE_FAILURE_REASONS: Array<{\n flag: number,\n failure: AnimationFailureReasons,\n}> =\n [\n {\n flag: 1 << 0,\n failure: AnimationFailureReasons.ACCELERATED_ANIMATIONS_DISABLED,\n },\n {\n flag: 1 << 1,\n failure: AnimationFailureReasons.EFFECT_SUPPRESSED_BY_DEVTOOLS,\n },\n {\n flag: 1 << 2,\n failure: AnimationFailureReasons.INVALID_ANIMATION_OR_EFFECT,\n },\n {\n flag: 1 << 3,\n failure: AnimationFailureReasons.EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS,\n },\n {\n flag: 1 << 4,\n failure: AnimationFailureReasons.EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE,\n },\n {\n flag: 1 << 5,\n failure: AnimationFailureReasons.TARGET_HAS_INVALID_COMPOSITING_STATE,\n },\n {\n flag: 1 << 6,\n failure: AnimationFailureReasons.TARGET_HAS_INCOMPATIBLE_ANIMATIONS,\n },\n {\n flag: 1 << 7,\n failure: AnimationFailureReasons.TARGET_HAS_CSS_OFFSET,\n },\n // The failure 1 << 8 is marked as obsolete in Blink\n {\n flag: 1 << 9,\n failure: AnimationFailureReasons.ANIMATION_AFFECTS_NON_CSS_PROPERTIES,\n },\n {\n flag: 1 << 10,\n failure: AnimationFailureReasons.TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET,\n },\n {\n flag: 1 << 11,\n failure: AnimationFailureReasons.TRANSFROM_BOX_SIZE_DEPENDENT,\n },\n {\n flag: 1 << 12,\n failure: AnimationFailureReasons.FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS,\n },\n {\n flag: 1 << 13,\n failure: AnimationFailureReasons.UNSUPPORTED_CSS_PROPERTY,\n },\n // The failure 1 << 14 is marked as obsolete in Blink\n {\n flag: 1 << 15,\n failure: AnimationFailureReasons.MIXED_KEYFRAME_VALUE_TYPES,\n },\n {\n flag: 1 << 16,\n failure: AnimationFailureReasons.TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE,\n },\n {\n flag: 1 << 17,\n failure: AnimationFailureReasons.ANIMATION_HAS_NO_VISIBLE_CHANGE,\n },\n {\n flag: 1 << 18,\n failure: AnimationFailureReasons.AFFECTS_IMPORTANT_PROPERTY,\n },\n {\n flag: 1 << 19,\n failure: AnimationFailureReasons.SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY,\n },\n ] as const;\n\n// 500ms window.\n// Use this window to consider events and requests that may have caused a layout shift.\nconst ROOT_CAUSE_WINDOW = Helpers.Timing.secondsToMicro(Types.Timing.Seconds(0.5));\n\nexport interface UnsizedImage {\n backendNodeId: Protocol.DOM.BackendNodeId;\n paintImageEvent: Types.Events.PaintImage;\n}\n\nexport interface IframeRootCause {\n frame: string;\n url?: string;\n}\n\nexport interface LayoutShiftRootCausesData {\n iframes: IframeRootCause[];\n webFonts: Types.Events.SyntheticNetworkRequest[];\n nonCompositedAnimations: NoncompositedAnimationFailure[];\n unsizedImages: UnsizedImage[];\n}\n\n/**\n * Returns if an event happens within the root cause window, before the target event.\n * ROOT_CAUSE_WINDOW v target event\n * |------------------------|=======================\n */\nfunction isInRootCauseWindow(event: Types.Events.Event, targetEvent: Types.Events.Event): boolean {\n const eventEnd = event.dur ? event.ts + event.dur : event.ts;\n return eventEnd < targetEvent.ts && eventEnd >= targetEvent.ts - ROOT_CAUSE_WINDOW;\n}\n\nexport function getNonCompositedFailure(animationEvent: Types.Events.SyntheticAnimationPair):\n NoncompositedAnimationFailure[] {\n const failures: NoncompositedAnimationFailure[] = [];\n const beginEvent = animationEvent.args.data.beginEvent;\n const instantEvents = animationEvent.args.data.instantEvents || [];\n /**\n * Animation events containing composite information are ASYNC_NESTABLE_INSTANT ('n').\n * An animation may also contain multiple 'n' events, so we look through those with useful non-composited data.\n */\n for (const event of instantEvents) {\n const failureMask = event.args.data.compositeFailed;\n const unsupportedProperties = event.args.data.unsupportedProperties;\n if (!failureMask) {\n continue;\n }\n const failureReasons =\n ACTIONABLE_FAILURE_REASONS.filter(reason => failureMask & reason.flag).map(reason => reason.failure);\n const failure: NoncompositedAnimationFailure = {\n name: beginEvent.args.data.displayName,\n failureReasons,\n unsupportedProperties,\n animation: animationEvent,\n };\n failures.push(failure);\n }\n return failures;\n}\n\nfunction getNonCompositedFailureRootCauses(\n animationEvents: Types.Events.SyntheticAnimationPair[],\n prePaintEvents: Types.Events.PrePaint[],\n shiftsByPrePaint: Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>,\n rootCausesByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>,\n ): NoncompositedAnimationFailure[] {\n const allAnimationFailures: NoncompositedAnimationFailure[] = [];\n for (const animation of animationEvents) {\n /**\n * Animation events containing composite information are ASYNC_NESTABLE_INSTANT ('n').\n * An animation may also contain multiple 'n' events, so we look through those with useful non-composited data.\n */\n const failures = getNonCompositedFailure(animation);\n if (!failures) {\n continue;\n }\n allAnimationFailures.push(...failures);\n\n const nextPrePaint = getNextEvent(prePaintEvents, animation) as Types.Events.PrePaint | null;\n // If no following prePaint, this is not a root cause.\n if (!nextPrePaint) {\n continue;\n }\n\n // If the animation event is outside the ROOT_CAUSE_WINDOW, it could not be a root cause.\n if (!isInRootCauseWindow(animation, nextPrePaint)) {\n continue;\n }\n\n const shifts = shiftsByPrePaint.get(nextPrePaint);\n // if no layout shift(s), this is not a root cause.\n if (!shifts) {\n continue;\n }\n\n for (const shift of shifts) {\n const rootCausesForShift = rootCausesByShift.get(shift);\n if (!rootCausesForShift) {\n throw new Error('Unaccounted shift');\n }\n rootCausesForShift.nonCompositedAnimations.push(...failures);\n }\n }\n\n return allAnimationFailures;\n}\n\n/**\n * Given an array of layout shift and PrePaint events, returns a mapping from\n * PrePaint events to layout shifts dispatched within it.\n */\nfunction getShiftsByPrePaintEvents(\n layoutShifts: Types.Events.SyntheticLayoutShift[],\n prePaintEvents: Types.Events.PrePaint[],\n ): Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]> {\n // Maps from PrePaint events to LayoutShifts that occurred in each one.\n const shiftsByPrePaint = new Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>();\n\n // Associate all shifts to their corresponding PrePaint.\n for (const prePaintEvent of prePaintEvents) {\n const firstShiftIndex =\n Platform.ArrayUtilities.nearestIndexFromBeginning(layoutShifts, shift => shift.ts >= prePaintEvent.ts);\n if (firstShiftIndex === null) {\n // No layout shifts registered after this PrePaint start. Continue.\n continue;\n }\n for (let i = firstShiftIndex; i < layoutShifts.length; i++) {\n const shift = layoutShifts[i];\n if (shift.ts >= prePaintEvent.ts && shift.ts <= prePaintEvent.ts + prePaintEvent.dur) {\n const shiftsInPrePaint = Platform.MapUtilities.getWithDefault(shiftsByPrePaint, prePaintEvent, () => []);\n shiftsInPrePaint.push(shift);\n }\n if (shift.ts > prePaintEvent.ts + prePaintEvent.dur) {\n // Reached all layoutShifts of this PrePaint. Break out to continue with the next prePaint event.\n break;\n }\n }\n }\n return shiftsByPrePaint;\n}\n\n/**\n * Given a source event list, this returns the first event of that list that directly follows the target event.\n */\nfunction getNextEvent(sourceEvents: Types.Events.Event[], targetEvent: Types.Events.Event): Types.Events.Event|\n undefined {\n const index = Platform.ArrayUtilities.nearestIndexFromBeginning(\n sourceEvents, source => source.ts > targetEvent.ts + (targetEvent.dur || 0));\n // No PrePaint event registered after this event\n if (index === null) {\n return undefined;\n }\n\n return sourceEvents[index];\n}\n\n/**\n * An Iframe is considered a root cause if the iframe event occurs before a prePaint event\n * and within this prePaint event a layout shift(s) occurs.\n */\nfunction getIframeRootCauses(\n data: Handlers.Types.HandlerData, iframeCreatedEvents: readonly Types.Events.RenderFrameImplCreateChildFrame[],\n prePaintEvents: Types.Events.PrePaint[],\n shiftsByPrePaint: Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>,\n rootCausesByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>,\n domLoadingEvents: readonly Types.Events.DomLoading[]):\n Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData> {\n for (const iframeEvent of iframeCreatedEvents) {\n const nextPrePaint = getNextEvent(prePaintEvents, iframeEvent) as Types.Events.PrePaint | null;\n // If no following prePaint, this is not a root cause.\n if (!nextPrePaint) {\n continue;\n }\n const shifts = shiftsByPrePaint.get(nextPrePaint);\n // if no layout shift(s), this is not a root cause.\n if (!shifts) {\n continue;\n }\n for (const shift of shifts) {\n const rootCausesForShift = rootCausesByShift.get(shift);\n if (!rootCausesForShift) {\n throw new Error('Unaccounted shift');\n }\n\n // Look for the first dom event that occurs within the bounds of the iframe event.\n // This contains the frame id.\n const domEvent = domLoadingEvents.find(e => {\n const maxIframe = Types.Timing.Micro(iframeEvent.ts + (iframeEvent.dur ?? 0));\n return e.ts >= iframeEvent.ts && e.ts <= maxIframe;\n });\n if (domEvent?.args.frame) {\n const frame = domEvent.args.frame;\n\n let url;\n const processes = data.Meta.rendererProcessesByFrame.get(frame);\n if (processes && processes.size > 0) {\n url = [...processes.values()][0]?.[0].frame.url;\n }\n\n rootCausesForShift.iframes.push({frame, url});\n }\n }\n }\n return rootCausesByShift;\n}\n\n/**\n * An unsized image is considered a root cause if its PaintImage can be correlated to a\n * layout shift. We can correlate PaintImages with unsized images by their matching nodeIds.\n * X <- layout shift\n * |----------------|\n * ^ PrePaint event |-----|\n * ^ PaintImage\n */\nfunction getUnsizedImageRootCauses(\n unsizedImageEvents: readonly Types.Events.LayoutImageUnsized[], paintImageEvents: Types.Events.PaintImage[],\n shiftsByPrePaint: Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>,\n rootCausesByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>):\n Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData> {\n shiftsByPrePaint.forEach((shifts, prePaint) => {\n const paintImage = getNextEvent(paintImageEvents, prePaint) as Types.Events.PaintImage | null;\n if (!paintImage) {\n return;\n }\n // The unsized image corresponds to this PaintImage.\n const matchingNode =\n unsizedImageEvents.find(unsizedImage => unsizedImage.args.data.nodeId === paintImage.args.data.nodeId);\n if (!matchingNode) {\n return;\n }\n // The unsized image is a potential root cause of all the shifts of this prePaint.\n for (const shift of shifts) {\n const rootCausesForShift = rootCausesByShift.get(shift);\n if (!rootCausesForShift) {\n throw new Error('Unaccounted shift');\n }\n rootCausesForShift.unsizedImages.push({\n backendNodeId: matchingNode.args.data.nodeId,\n paintImageEvent: paintImage,\n });\n }\n });\n return rootCausesByShift;\n}\n\nexport function isCLSCulpritsInsight(insight: InsightModel): insight is CLSCulpritsInsightModel {\n return insight.insightKey === InsightKeys.CLS_CULPRITS;\n}\n\n/**\n * A font request is considered a root cause if the request occurs before a prePaint event\n * and within this prePaint event a layout shift(s) occurs. Additionally, this font request should\n * happen within the ROOT_CAUSE_WINDOW of the prePaint event.\n */\nfunction getFontRootCauses(\n networkRequests: Types.Events.SyntheticNetworkRequest[], prePaintEvents: Types.Events.PrePaint[],\n shiftsByPrePaint: Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>,\n rootCausesByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>):\n Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData> {\n const fontRequests =\n networkRequests.filter(req => req.args.data.resourceType === 'Font' && req.args.data.mimeType.startsWith('font'));\n\n for (const req of fontRequests) {\n const nextPrePaint = getNextEvent(prePaintEvents, req) as Types.Events.PrePaint | null;\n if (!nextPrePaint) {\n continue;\n }\n\n // If the req is outside the ROOT_CAUSE_WINDOW, it could not be a root cause.\n if (!isInRootCauseWindow(req, nextPrePaint)) {\n continue;\n }\n\n // Get the shifts that belong to this prepaint\n const shifts = shiftsByPrePaint.get(nextPrePaint);\n\n // if no layout shift(s) in this prePaint, the request is not a root cause.\n if (!shifts) {\n continue;\n }\n // Include the root cause to the shifts in this prePaint.\n for (const shift of shifts) {\n const rootCausesForShift = rootCausesByShift.get(shift);\n if (!rootCausesForShift) {\n throw new Error('Unaccounted shift');\n }\n rootCausesForShift.webFonts.push(req);\n }\n }\n return rootCausesByShift;\n}\n\n/**\n * Returns the top 3 shift root causes based on the given cluster.\n */\nfunction getTopCulprits(\n cluster: Types.Events.SyntheticLayoutShiftCluster,\n culpritsByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>): LayoutShiftItem[] {\n const MAX_TOP_CULPRITS = 3;\n const causes: LayoutShiftItem[] = [];\n\n const shifts = cluster.events;\n for (const shift of shifts) {\n const culprits = culpritsByShift.get(shift);\n if (!culprits) {\n continue;\n }\n\n const fontReq = culprits.webFonts;\n const iframes = culprits.iframes;\n const animations = culprits.nonCompositedAnimations;\n const unsizedImages = culprits.unsizedImages;\n\n for (let i = 0; i < fontReq.length && causes.length < MAX_TOP_CULPRITS; i++) {\n causes.push({type: LayoutShiftType.WEB_FONT, description: i18nString(UIStrings.webFont)});\n }\n for (let i = 0; i < iframes.length && causes.length < MAX_TOP_CULPRITS; i++) {\n causes.push({type: LayoutShiftType.IFRAMES, description: i18nString(UIStrings.injectedIframe)});\n }\n for (let i = 0; i < animations.length && causes.length < MAX_TOP_CULPRITS; i++) {\n causes.push({type: LayoutShiftType.ANIMATIONS, description: i18nString(UIStrings.animation)});\n }\n for (let i = 0; i < unsizedImages.length && causes.length < MAX_TOP_CULPRITS; i++) {\n causes.push({\n type: LayoutShiftType.UNSIZED_IMAGE,\n description: i18nString(UIStrings.unsizedImage),\n url: unsizedImages[i].paintImageEvent.args.data.url || '',\n backendNodeId: unsizedImages[i].backendNodeId,\n frame: unsizedImages[i].paintImageEvent.args.data.frame || '',\n });\n }\n\n if (causes.length >= MAX_TOP_CULPRITS) {\n break;\n }\n }\n\n return causes.slice(0, MAX_TOP_CULPRITS);\n}\n\nfunction finalize(partialModel: PartialInsightModel<CLSCulpritsInsightModel>): CLSCulpritsInsightModel {\n let state: CLSCulpritsInsightModel['state'] = 'pass';\n if (partialModel.worstCluster) {\n const classification = Handlers.ModelHandlers.LayoutShifts.scoreClassificationForLayoutShift(\n partialModel.worstCluster.clusterCumulativeScore);\n if (classification === Handlers.ModelHandlers.PageLoadMetrics.ScoreClassification.GOOD) {\n state = 'informative';\n } else {\n state = 'fail';\n }\n }\n\n return {\n insightKey: InsightKeys.CLS_CULPRITS,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.CLS,\n state,\n ...partialModel,\n };\n}\n\nexport function generateInsight(data: Handlers.Types.HandlerData, context: InsightSetContext): CLSCulpritsInsightModel {\n const isWithinContext = (event: Types.Events.Event): boolean => Helpers.Timing.eventIsInBounds(event, context.bounds);\n\n const compositeAnimationEvents = data.Animations.animations.filter(isWithinContext);\n const iframeEvents = data.LayoutShifts.renderFrameImplCreateChildFrameEvents.filter(isWithinContext);\n const networkRequests = data.NetworkRequests.byTime.filter(isWithinContext);\n const domLoadingEvents = data.LayoutShifts.domLoadingEvents.filter(isWithinContext);\n const unsizedImageEvents = data.LayoutShifts.layoutImageUnsizedEvents.filter(isWithinContext);\n\n const clusterKey = context.navigation ? context.navigationId : Types.Events.NO_NAVIGATION;\n const clusters = data.LayoutShifts.clustersByNavigationId.get(clusterKey) ?? [];\n const clustersByScore = [...clusters].sort((a, b) => b.clusterCumulativeScore - a.clusterCumulativeScore);\n const worstCluster = clustersByScore.at(0);\n const layoutShifts = clusters.flatMap(cluster => cluster.events);\n const prePaintEvents = data.LayoutShifts.prePaintEvents.filter(isWithinContext);\n const paintImageEvents = data.LayoutShifts.paintImageEvents.filter(isWithinContext);\n\n // Get root causes.\n const rootCausesByShift = new Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>();\n const shiftsByPrePaint = getShiftsByPrePaintEvents(layoutShifts, prePaintEvents);\n\n for (const shift of layoutShifts) {\n rootCausesByShift.set(shift, {iframes: [], webFonts: [], nonCompositedAnimations: [], unsizedImages: []});\n }\n\n // Populate root causes for rootCausesByShift.\n getIframeRootCauses(data, iframeEvents, prePaintEvents, shiftsByPrePaint, rootCausesByShift, domLoadingEvents);\n getFontRootCauses(networkRequests, prePaintEvents, shiftsByPrePaint, rootCausesByShift);\n getUnsizedImageRootCauses(unsizedImageEvents, paintImageEvents, shiftsByPrePaint, rootCausesByShift);\n const animationFailures =\n getNonCompositedFailureRootCauses(compositeAnimationEvents, prePaintEvents, shiftsByPrePaint, rootCausesByShift);\n\n const relatedEvents: Types.Events.Event[] = [...layoutShifts];\n if (worstCluster) {\n relatedEvents.push(worstCluster);\n }\n\n const topCulpritsByCluster = new Map<Types.Events.SyntheticLayoutShiftCluster, LayoutShiftItem[]>();\n for (const cluster of clusters) {\n topCulpritsByCluster.set(cluster, getTopCulprits(cluster, rootCausesByShift));\n }\n\n return finalize({\n relatedEvents,\n animationFailures,\n shifts: rootCausesByShift,\n clusters,\n worstCluster,\n topCulpritsByCluster,\n });\n}\n\nexport function createOverlays(model: CLSCulpritsInsightModel): Types.Overlays.Overlay[] {\n const clustersByScore = model.clusters.toSorted((a, b) => b.clusterCumulativeScore - a.clusterCumulativeScore) ?? [];\n const worstCluster = clustersByScore[0];\n if (!worstCluster) {\n return [];\n }\n\n const range = Types.Timing.Micro(worstCluster.dur ?? 0);\n const max = Types.Timing.Micro(worstCluster.ts + range);\n\n return [{\n type: 'TIMESPAN_BREAKDOWN',\n sections: [\n {\n bounds: {min: worstCluster.ts, range, max},\n label: i18nString(UIStrings.worstLayoutShiftCluster),\n showDuration: false,\n },\n ],\n // This allows for the overlay to sit over the layout shift.\n entry: worstCluster.events[0],\n renderLocation: 'ABOVE_EVENT',\n }];\n}\n"]}
|
|
1
|
+
{"version":3,"file":"CLSCulprits.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/CLSCulprits.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Platform from '../../../core/platform/platform.js';\nimport type * as Protocol from '../../../generated/protocol.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /** Title of an insight that provides details about why elements shift/move on the page. The causes for these shifts are referred to as culprits (\"reasons\"). */\n title: 'Layout shift culprits',\n /**\n * @description Description of a DevTools insight that identifies the reasons that elements shift on the page.\n * This is displayed after a user expands the section to see more. No character length limits.\n */\n description:\n 'Layout shifts occur when elements move absent any user interaction. [Investigate the causes of layout shifts](https://developer.chrome.com/docs/performance/insights/cls-culprit), such as elements being added, removed, or their fonts changing as the page loads.',\n /**\n * @description Text indicating the worst layout shift cluster.\n */\n worstLayoutShiftCluster: 'Worst layout shift cluster',\n /**\n * @description Text indicating the worst layout shift cluster.\n */\n worstCluster: 'Worst cluster',\n /**\n * @description Text indicating a layout shift cluster and its start time.\n * @example {32 ms} PH1\n */\n layoutShiftCluster: 'Layout shift cluster @ {PH1}',\n /**\n * @description Text indicating the biggest reasons for the layout shifts.\n */\n topCulprits: 'Top layout shift culprits',\n /**\n * @description Text for a culprit type of Injected iframe.\n */\n injectedIframe: 'Injected iframe',\n /**\n * @description Text for a culprit type of web font request.\n */\n webFont: 'Web font',\n /**\n * @description Text for a culprit type of Animation.\n */\n animation: 'Animation',\n /**\n * @description Text for a culprit type of Unsized image.\n */\n unsizedImage: 'Unsized image element',\n /**\n * @description Text status when there were no layout shifts detected.\n */\n noLayoutShifts: 'No layout shifts',\n /**\n * @description Text status when there no layout shifts culprits/root causes were found.\n */\n noCulprits: 'Could not detect any layout shift culprits',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/CLSCulprits.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type CLSCulpritsInsightModel = InsightModel<typeof UIStrings, {\n animationFailures: readonly NoncompositedAnimationFailure[],\n shifts: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>,\n clusters: Types.Events.SyntheticLayoutShiftCluster[],\n worstCluster: Types.Events.SyntheticLayoutShiftCluster | undefined,\n /** The top 3 shift root causes for each cluster. */\n topCulpritsByCluster: Map<Types.Events.SyntheticLayoutShiftCluster, LayoutShiftItem[]>,\n}>;\n\nexport enum AnimationFailureReasons {\n ACCELERATED_ANIMATIONS_DISABLED = 'ACCELERATED_ANIMATIONS_DISABLED',\n EFFECT_SUPPRESSED_BY_DEVTOOLS = 'EFFECT_SUPPRESSED_BY_DEVTOOLS',\n INVALID_ANIMATION_OR_EFFECT = 'INVALID_ANIMATION_OR_EFFECT',\n EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS = 'EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS',\n EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE = 'EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE',\n TARGET_HAS_INVALID_COMPOSITING_STATE = 'TARGET_HAS_INVALID_COMPOSITING_STATE',\n TARGET_HAS_INCOMPATIBLE_ANIMATIONS = 'TARGET_HAS_INCOMPATIBLE_ANIMATIONS',\n TARGET_HAS_CSS_OFFSET = 'TARGET_HAS_CSS_OFFSET',\n ANIMATION_AFFECTS_NON_CSS_PROPERTIES = 'ANIMATION_AFFECTS_NON_CSS_PROPERTIES',\n TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET =\n 'TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET',\n TRANSFROM_BOX_SIZE_DEPENDENT = 'TRANSFROM_BOX_SIZE_DEPENDENT',\n FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS = 'FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS',\n UNSUPPORTED_CSS_PROPERTY = 'UNSUPPORTED_CSS_PROPERTY',\n MIXED_KEYFRAME_VALUE_TYPES = 'MIXED_KEYFRAME_VALUE_TYPES',\n TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE = 'TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE',\n ANIMATION_HAS_NO_VISIBLE_CHANGE = 'ANIMATION_HAS_NO_VISIBLE_CHANGE',\n AFFECTS_IMPORTANT_PROPERTY = 'AFFECTS_IMPORTANT_PROPERTY',\n SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY = 'SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY',\n}\n\nexport enum LayoutShiftType {\n WEB_FONT = 0,\n IFRAMES = 1,\n ANIMATIONS = 2,\n UNSIZED_IMAGE = 3,\n}\n\nexport type LayoutShiftItem = {\n type: LayoutShiftType.UNSIZED_IMAGE,\n description: Platform.UIString.LocalizedString,\n url: string,\n backendNodeId: Protocol.DOM.BackendNodeId,\n frame: string,\n}|{\n type: Exclude<LayoutShiftType, LayoutShiftType.UNSIZED_IMAGE>,\n description: Platform.UIString.LocalizedString,\n};\n\nexport interface NoncompositedAnimationFailure {\n /**\n * Animation name.\n */\n name?: string;\n /**\n * Failure reason based on mask number defined in\n * https://source.chromium.org/search?q=f:compositor_animations.h%20%22enum%20FailureReason%22.\n */\n failureReasons: AnimationFailureReasons[];\n /**\n * Unsupported properties.\n */\n unsupportedProperties?: Types.Events.Animation['args']['data']['unsupportedProperties'];\n /**\n * Animation event.\n */\n animation?: Types.Events.SyntheticAnimationPair;\n}\n\n/**\n * Each failure reason is represented by a bit flag. The bit shift operator '<<' is used to define\n * which bit corresponds to each failure reason.\n * https://source.chromium.org/search?q=f:compositor_animations.h%20%22enum%20FailureReason%22\n */\nconst ACTIONABLE_FAILURE_REASONS: Array<{\n flag: number,\n failure: AnimationFailureReasons,\n}> =\n [\n {\n flag: 1 << 0,\n failure: AnimationFailureReasons.ACCELERATED_ANIMATIONS_DISABLED,\n },\n {\n flag: 1 << 1,\n failure: AnimationFailureReasons.EFFECT_SUPPRESSED_BY_DEVTOOLS,\n },\n {\n flag: 1 << 2,\n failure: AnimationFailureReasons.INVALID_ANIMATION_OR_EFFECT,\n },\n {\n flag: 1 << 3,\n failure: AnimationFailureReasons.EFFECT_HAS_UNSUPPORTED_TIMING_PARAMS,\n },\n {\n flag: 1 << 4,\n failure: AnimationFailureReasons.EFFECT_HAS_NON_REPLACE_COMPOSITE_MODE,\n },\n {\n flag: 1 << 5,\n failure: AnimationFailureReasons.TARGET_HAS_INVALID_COMPOSITING_STATE,\n },\n {\n flag: 1 << 6,\n failure: AnimationFailureReasons.TARGET_HAS_INCOMPATIBLE_ANIMATIONS,\n },\n {\n flag: 1 << 7,\n failure: AnimationFailureReasons.TARGET_HAS_CSS_OFFSET,\n },\n // The failure 1 << 8 is marked as obsolete in Blink\n {\n flag: 1 << 9,\n failure: AnimationFailureReasons.ANIMATION_AFFECTS_NON_CSS_PROPERTIES,\n },\n {\n flag: 1 << 10,\n failure: AnimationFailureReasons.TRANSFORM_RELATED_PROPERTY_CANNOT_BE_ACCELERATED_ON_TARGET,\n },\n {\n flag: 1 << 11,\n failure: AnimationFailureReasons.TRANSFROM_BOX_SIZE_DEPENDENT,\n },\n {\n flag: 1 << 12,\n failure: AnimationFailureReasons.FILTER_RELATED_PROPERTY_MAY_MOVE_PIXELS,\n },\n {\n flag: 1 << 13,\n failure: AnimationFailureReasons.UNSUPPORTED_CSS_PROPERTY,\n },\n // The failure 1 << 14 is marked as obsolete in Blink\n {\n flag: 1 << 15,\n failure: AnimationFailureReasons.MIXED_KEYFRAME_VALUE_TYPES,\n },\n {\n flag: 1 << 16,\n failure: AnimationFailureReasons.TIMELINE_SOURCE_HAS_INVALID_COMPOSITING_STATE,\n },\n {\n flag: 1 << 17,\n failure: AnimationFailureReasons.ANIMATION_HAS_NO_VISIBLE_CHANGE,\n },\n {\n flag: 1 << 18,\n failure: AnimationFailureReasons.AFFECTS_IMPORTANT_PROPERTY,\n },\n {\n flag: 1 << 19,\n failure: AnimationFailureReasons.SVG_TARGET_HAS_INDEPENDENT_TRANSFORM_PROPERTY,\n },\n ] as const;\n\n// 500ms window.\n// Use this window to consider events and requests that may have caused a layout shift.\nconst ROOT_CAUSE_WINDOW = Helpers.Timing.secondsToMicro(Types.Timing.Seconds(0.5));\n\nexport interface UnsizedImage {\n backendNodeId: Protocol.DOM.BackendNodeId;\n paintImageEvent: Types.Events.PaintImage;\n}\n\nexport interface IframeRootCause {\n frame: string;\n url?: string;\n}\n\nexport interface LayoutShiftRootCausesData {\n iframes: IframeRootCause[];\n webFonts: Types.Events.SyntheticNetworkRequest[];\n nonCompositedAnimations: NoncompositedAnimationFailure[];\n unsizedImages: UnsizedImage[];\n}\n\n/**\n * Returns if an event happens within the root cause window, before the target event.\n * ROOT_CAUSE_WINDOW v target event\n * |------------------------|=======================\n */\nfunction isInRootCauseWindow(event: Types.Events.Event, targetEvent: Types.Events.Event): boolean {\n const eventEnd = event.dur ? event.ts + event.dur : event.ts;\n return eventEnd < targetEvent.ts && eventEnd >= targetEvent.ts - ROOT_CAUSE_WINDOW;\n}\n\nexport function getNonCompositedFailure(animationEvent: Types.Events.SyntheticAnimationPair):\n NoncompositedAnimationFailure[] {\n const failures: NoncompositedAnimationFailure[] = [];\n const beginEvent = animationEvent.args.data.beginEvent;\n const instantEvents = animationEvent.args.data.instantEvents || [];\n /**\n * Animation events containing composite information are ASYNC_NESTABLE_INSTANT ('n').\n * An animation may also contain multiple 'n' events, so we look through those with useful non-composited data.\n */\n for (const event of instantEvents) {\n const failureMask = event.args.data.compositeFailed;\n const unsupportedProperties = event.args.data.unsupportedProperties;\n if (!failureMask) {\n continue;\n }\n const failureReasons =\n ACTIONABLE_FAILURE_REASONS.filter(reason => failureMask & reason.flag).map(reason => reason.failure);\n const failure: NoncompositedAnimationFailure = {\n name: beginEvent.args.data.displayName,\n failureReasons,\n unsupportedProperties,\n animation: animationEvent,\n };\n failures.push(failure);\n }\n return failures;\n}\n\nfunction getNonCompositedFailureRootCauses(\n animationEvents: Types.Events.SyntheticAnimationPair[],\n prePaintEvents: Types.Events.PrePaint[],\n shiftsByPrePaint: Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>,\n rootCausesByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>,\n ): NoncompositedAnimationFailure[] {\n const allAnimationFailures: NoncompositedAnimationFailure[] = [];\n for (const animation of animationEvents) {\n /**\n * Animation events containing composite information are ASYNC_NESTABLE_INSTANT ('n').\n * An animation may also contain multiple 'n' events, so we look through those with useful non-composited data.\n */\n const failures = getNonCompositedFailure(animation);\n if (!failures) {\n continue;\n }\n allAnimationFailures.push(...failures);\n\n const nextPrePaint = getNextEvent(prePaintEvents, animation) as Types.Events.PrePaint | null;\n // If no following prePaint, this is not a root cause.\n if (!nextPrePaint) {\n continue;\n }\n\n // If the animation event is outside the ROOT_CAUSE_WINDOW, it could not be a root cause.\n if (!isInRootCauseWindow(animation, nextPrePaint)) {\n continue;\n }\n\n const shifts = shiftsByPrePaint.get(nextPrePaint);\n // if no layout shift(s), this is not a root cause.\n if (!shifts) {\n continue;\n }\n\n for (const shift of shifts) {\n const rootCausesForShift = rootCausesByShift.get(shift);\n if (!rootCausesForShift) {\n throw new Error('Unaccounted shift');\n }\n rootCausesForShift.nonCompositedAnimations.push(...failures);\n }\n }\n\n return allAnimationFailures;\n}\n\n/**\n * Given an array of layout shift and PrePaint events, returns a mapping from\n * PrePaint events to layout shifts dispatched within it.\n */\nfunction getShiftsByPrePaintEvents(\n layoutShifts: Types.Events.SyntheticLayoutShift[],\n prePaintEvents: Types.Events.PrePaint[],\n ): Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]> {\n // Maps from PrePaint events to LayoutShifts that occurred in each one.\n const shiftsByPrePaint = new Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>();\n\n // Associate all shifts to their corresponding PrePaint.\n for (const prePaintEvent of prePaintEvents) {\n const firstShiftIndex =\n Platform.ArrayUtilities.nearestIndexFromBeginning(layoutShifts, shift => shift.ts >= prePaintEvent.ts);\n if (firstShiftIndex === null) {\n // No layout shifts registered after this PrePaint start. Continue.\n continue;\n }\n for (let i = firstShiftIndex; i < layoutShifts.length; i++) {\n const shift = layoutShifts[i];\n if (shift.ts >= prePaintEvent.ts && shift.ts <= prePaintEvent.ts + prePaintEvent.dur) {\n const shiftsInPrePaint = Platform.MapUtilities.getWithDefault(shiftsByPrePaint, prePaintEvent, () => []);\n shiftsInPrePaint.push(shift);\n }\n if (shift.ts > prePaintEvent.ts + prePaintEvent.dur) {\n // Reached all layoutShifts of this PrePaint. Break out to continue with the next prePaint event.\n break;\n }\n }\n }\n return shiftsByPrePaint;\n}\n\n/**\n * Given a source event list, this returns the first event of that list that directly follows the target event.\n */\nfunction getNextEvent(sourceEvents: Types.Events.Event[], targetEvent: Types.Events.Event): Types.Events.Event|\n undefined {\n const index = Platform.ArrayUtilities.nearestIndexFromBeginning(\n sourceEvents, source => source.ts > targetEvent.ts + (targetEvent.dur || 0));\n // No PrePaint event registered after this event\n if (index === null) {\n return undefined;\n }\n\n return sourceEvents[index];\n}\n\n/**\n * An Iframe is considered a root cause if the iframe event occurs before a prePaint event\n * and within this prePaint event a layout shift(s) occurs.\n */\nfunction getIframeRootCauses(\n data: Handlers.Types.HandlerData, iframeCreatedEvents: readonly Types.Events.RenderFrameImplCreateChildFrame[],\n prePaintEvents: Types.Events.PrePaint[],\n shiftsByPrePaint: Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>,\n rootCausesByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>,\n domLoadingEvents: readonly Types.Events.DomLoading[]):\n Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData> {\n for (const iframeEvent of iframeCreatedEvents) {\n const nextPrePaint = getNextEvent(prePaintEvents, iframeEvent) as Types.Events.PrePaint | null;\n // If no following prePaint, this is not a root cause.\n if (!nextPrePaint) {\n continue;\n }\n const shifts = shiftsByPrePaint.get(nextPrePaint);\n // if no layout shift(s), this is not a root cause.\n if (!shifts) {\n continue;\n }\n for (const shift of shifts) {\n const rootCausesForShift = rootCausesByShift.get(shift);\n if (!rootCausesForShift) {\n throw new Error('Unaccounted shift');\n }\n\n // Look for the first dom event that occurs within the bounds of the iframe event.\n // This contains the frame id.\n const domEvent = domLoadingEvents.find(e => {\n const maxIframe = Types.Timing.Micro(iframeEvent.ts + (iframeEvent.dur ?? 0));\n return e.ts >= iframeEvent.ts && e.ts <= maxIframe;\n });\n if (domEvent?.args.frame) {\n const frame = domEvent.args.frame;\n\n let url;\n const processes = data.Meta.rendererProcessesByFrame.get(frame);\n if (processes && processes.size > 0) {\n url = [...processes.values()][0]?.[0].frame.url;\n }\n\n rootCausesForShift.iframes.push({frame, url});\n }\n }\n }\n return rootCausesByShift;\n}\n\n/**\n * An unsized image is considered a root cause if its PaintImage can be correlated to a\n * layout shift. We can correlate PaintImages with unsized images by their matching nodeIds.\n * X <- layout shift\n * |----------------|\n * ^ PrePaint event |-----|\n * ^ PaintImage\n */\nfunction getUnsizedImageRootCauses(\n unsizedImageEvents: readonly Types.Events.LayoutImageUnsized[], paintImageEvents: Types.Events.PaintImage[],\n shiftsByPrePaint: Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>,\n rootCausesByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>):\n Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData> {\n shiftsByPrePaint.forEach((shifts, prePaint) => {\n const paintImage = getNextEvent(paintImageEvents, prePaint) as Types.Events.PaintImage | null;\n if (!paintImage) {\n return;\n }\n // The unsized image corresponds to this PaintImage.\n const matchingNode =\n unsizedImageEvents.find(unsizedImage => unsizedImage.args.data.nodeId === paintImage.args.data.nodeId);\n if (!matchingNode) {\n return;\n }\n // The unsized image is a potential root cause of all the shifts of this prePaint.\n for (const shift of shifts) {\n const rootCausesForShift = rootCausesByShift.get(shift);\n if (!rootCausesForShift) {\n throw new Error('Unaccounted shift');\n }\n rootCausesForShift.unsizedImages.push({\n backendNodeId: matchingNode.args.data.nodeId,\n paintImageEvent: paintImage,\n });\n }\n });\n return rootCausesByShift;\n}\n\nexport function isCLSCulpritsInsight(insight: InsightModel): insight is CLSCulpritsInsightModel {\n return insight.insightKey === InsightKeys.CLS_CULPRITS;\n}\n\n/**\n * A font request is considered a root cause if the request occurs before a prePaint event\n * and within this prePaint event a layout shift(s) occurs. Additionally, this font request should\n * happen within the ROOT_CAUSE_WINDOW of the prePaint event.\n */\nfunction getFontRootCauses(\n networkRequests: Types.Events.SyntheticNetworkRequest[], prePaintEvents: Types.Events.PrePaint[],\n shiftsByPrePaint: Map<Types.Events.PrePaint, Types.Events.SyntheticLayoutShift[]>,\n rootCausesByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>):\n Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData> {\n const fontRequests =\n networkRequests.filter(req => req.args.data.resourceType === 'Font' && req.args.data.mimeType.startsWith('font'));\n\n for (const req of fontRequests) {\n const nextPrePaint = getNextEvent(prePaintEvents, req) as Types.Events.PrePaint | null;\n if (!nextPrePaint) {\n continue;\n }\n\n // If the req is outside the ROOT_CAUSE_WINDOW, it could not be a root cause.\n if (!isInRootCauseWindow(req, nextPrePaint)) {\n continue;\n }\n\n // Get the shifts that belong to this prepaint\n const shifts = shiftsByPrePaint.get(nextPrePaint);\n\n // if no layout shift(s) in this prePaint, the request is not a root cause.\n if (!shifts) {\n continue;\n }\n // Include the root cause to the shifts in this prePaint.\n for (const shift of shifts) {\n const rootCausesForShift = rootCausesByShift.get(shift);\n if (!rootCausesForShift) {\n throw new Error('Unaccounted shift');\n }\n rootCausesForShift.webFonts.push(req);\n }\n }\n return rootCausesByShift;\n}\n\n/**\n * Returns the top 3 shift root causes based on the given cluster.\n */\nfunction getTopCulprits(\n cluster: Types.Events.SyntheticLayoutShiftCluster,\n culpritsByShift: Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>): LayoutShiftItem[] {\n const MAX_TOP_CULPRITS = 3;\n const causes: LayoutShiftItem[] = [];\n\n const shifts = cluster.events;\n for (const shift of shifts) {\n const culprits = culpritsByShift.get(shift);\n if (!culprits) {\n continue;\n }\n\n const fontReq = culprits.webFonts;\n const iframes = culprits.iframes;\n const animations = culprits.nonCompositedAnimations;\n const unsizedImages = culprits.unsizedImages;\n\n for (let i = 0; i < fontReq.length && causes.length < MAX_TOP_CULPRITS; i++) {\n causes.push({type: LayoutShiftType.WEB_FONT, description: i18nString(UIStrings.webFont)});\n }\n for (let i = 0; i < iframes.length && causes.length < MAX_TOP_CULPRITS; i++) {\n causes.push({type: LayoutShiftType.IFRAMES, description: i18nString(UIStrings.injectedIframe)});\n }\n for (let i = 0; i < animations.length && causes.length < MAX_TOP_CULPRITS; i++) {\n causes.push({type: LayoutShiftType.ANIMATIONS, description: i18nString(UIStrings.animation)});\n }\n for (let i = 0; i < unsizedImages.length && causes.length < MAX_TOP_CULPRITS; i++) {\n causes.push({\n type: LayoutShiftType.UNSIZED_IMAGE,\n description: i18nString(UIStrings.unsizedImage),\n url: unsizedImages[i].paintImageEvent.args.data.url || '',\n backendNodeId: unsizedImages[i].backendNodeId,\n frame: unsizedImages[i].paintImageEvent.args.data.frame || '',\n });\n }\n\n if (causes.length >= MAX_TOP_CULPRITS) {\n break;\n }\n }\n\n return causes.slice(0, MAX_TOP_CULPRITS);\n}\n\nfunction finalize(partialModel: PartialInsightModel<CLSCulpritsInsightModel>): CLSCulpritsInsightModel {\n let state: CLSCulpritsInsightModel['state'] = 'pass';\n if (partialModel.worstCluster) {\n const classification = Handlers.ModelHandlers.LayoutShifts.scoreClassificationForLayoutShift(\n partialModel.worstCluster.clusterCumulativeScore);\n if (classification === Handlers.ModelHandlers.PageLoadMetrics.ScoreClassification.GOOD) {\n state = 'informative';\n } else {\n state = 'fail';\n }\n }\n\n return {\n insightKey: InsightKeys.CLS_CULPRITS,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n docs: 'https://developer.chrome.com/docs/performance/insights/cls-culprit',\n category: InsightCategory.CLS,\n state,\n ...partialModel,\n };\n}\n\nexport function generateInsight(data: Handlers.Types.HandlerData, context: InsightSetContext): CLSCulpritsInsightModel {\n const isWithinContext = (event: Types.Events.Event): boolean => Helpers.Timing.eventIsInBounds(event, context.bounds);\n\n const compositeAnimationEvents = data.Animations.animations.filter(isWithinContext);\n const iframeEvents = data.LayoutShifts.renderFrameImplCreateChildFrameEvents.filter(isWithinContext);\n const networkRequests = data.NetworkRequests.byTime.filter(isWithinContext);\n const domLoadingEvents = data.LayoutShifts.domLoadingEvents.filter(isWithinContext);\n const unsizedImageEvents = data.LayoutShifts.layoutImageUnsizedEvents.filter(isWithinContext);\n\n const clusterKey = context.navigation ? context.navigationId : Types.Events.NO_NAVIGATION;\n const clusters = data.LayoutShifts.clustersByNavigationId.get(clusterKey) ?? [];\n const clustersByScore = [...clusters].sort((a, b) => b.clusterCumulativeScore - a.clusterCumulativeScore);\n const worstCluster = clustersByScore.at(0);\n const layoutShifts = clusters.flatMap(cluster => cluster.events);\n const prePaintEvents = data.LayoutShifts.prePaintEvents.filter(isWithinContext);\n const paintImageEvents = data.LayoutShifts.paintImageEvents.filter(isWithinContext);\n\n // Get root causes.\n const rootCausesByShift = new Map<Types.Events.SyntheticLayoutShift, LayoutShiftRootCausesData>();\n const shiftsByPrePaint = getShiftsByPrePaintEvents(layoutShifts, prePaintEvents);\n\n for (const shift of layoutShifts) {\n rootCausesByShift.set(shift, {iframes: [], webFonts: [], nonCompositedAnimations: [], unsizedImages: []});\n }\n\n // Populate root causes for rootCausesByShift.\n getIframeRootCauses(data, iframeEvents, prePaintEvents, shiftsByPrePaint, rootCausesByShift, domLoadingEvents);\n getFontRootCauses(networkRequests, prePaintEvents, shiftsByPrePaint, rootCausesByShift);\n getUnsizedImageRootCauses(unsizedImageEvents, paintImageEvents, shiftsByPrePaint, rootCausesByShift);\n const animationFailures =\n getNonCompositedFailureRootCauses(compositeAnimationEvents, prePaintEvents, shiftsByPrePaint, rootCausesByShift);\n\n const relatedEvents: Types.Events.Event[] = [...layoutShifts];\n if (worstCluster) {\n relatedEvents.push(worstCluster);\n }\n\n const topCulpritsByCluster = new Map<Types.Events.SyntheticLayoutShiftCluster, LayoutShiftItem[]>();\n for (const cluster of clusters) {\n topCulpritsByCluster.set(cluster, getTopCulprits(cluster, rootCausesByShift));\n }\n\n return finalize({\n relatedEvents,\n animationFailures,\n shifts: rootCausesByShift,\n clusters,\n worstCluster,\n topCulpritsByCluster,\n });\n}\n\nexport function createOverlays(model: CLSCulpritsInsightModel): Types.Overlays.Overlay[] {\n const clustersByScore = model.clusters.toSorted((a, b) => b.clusterCumulativeScore - a.clusterCumulativeScore) ?? [];\n const worstCluster = clustersByScore[0];\n if (!worstCluster) {\n return [];\n }\n\n const range = Types.Timing.Micro(worstCluster.dur ?? 0);\n const max = Types.Timing.Micro(worstCluster.ts + range);\n\n return [{\n type: 'TIMESPAN_BREAKDOWN',\n sections: [\n {\n bounds: {min: worstCluster.ts, range, max},\n label: i18nString(UIStrings.worstLayoutShiftCluster),\n showDuration: false,\n },\n ],\n // This allows for the overlay to sit over the layout shift.\n entry: worstCluster.events[0],\n renderLocation: 'ABOVE_EVENT',\n }];\n}\n"]}
|
|
@@ -10,7 +10,7 @@ export declare const UIStrings: {
|
|
|
10
10
|
/**
|
|
11
11
|
* @description Text to tell the user about how caching can help improve performance.
|
|
12
12
|
*/
|
|
13
|
-
readonly description: "A long cache lifetime can speed up repeat visits to your page. [Learn more](https://
|
|
13
|
+
readonly description: "A long cache lifetime can speed up repeat visits to your page. [Learn more about caching](https://developer.chrome.com/docs/performance/insights/cache).";
|
|
14
14
|
/**
|
|
15
15
|
* @description Column for a font loaded by the page to render text.
|
|
16
16
|
*/
|
|
@@ -14,7 +14,7 @@ export const UIStrings = {
|
|
|
14
14
|
/**
|
|
15
15
|
* @description Text to tell the user about how caching can help improve performance.
|
|
16
16
|
*/
|
|
17
|
-
description: 'A long cache lifetime can speed up repeat visits to your page. [Learn more](https://
|
|
17
|
+
description: 'A long cache lifetime can speed up repeat visits to your page. [Learn more about caching](https://developer.chrome.com/docs/performance/insights/cache).',
|
|
18
18
|
/**
|
|
19
19
|
* @description Column for a font loaded by the page to render text.
|
|
20
20
|
*/
|
|
@@ -43,6 +43,7 @@ function finalize(partialModel) {
|
|
|
43
43
|
strings: UIStrings,
|
|
44
44
|
title: i18nString(UIStrings.title),
|
|
45
45
|
description: i18nString(UIStrings.description),
|
|
46
|
+
docs: 'https://developer.chrome.com/docs/performance/insights/cache',
|
|
46
47
|
category: InsightCategory.ALL,
|
|
47
48
|
state: partialModel.requests.length > 0 ? 'fail' : 'pass',
|
|
48
49
|
...partialModel,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Cache.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/Cache.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 The Chromium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Protocol from '../../../generated/protocol.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Types from '../types/types.js';\n\nimport {metricSavingsForWastedBytes} from './Common.js';\nimport {linearInterpolation} from './Statistics.js';\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /**\n * @description Title of an insight that provides information and suggestions of resources that could improve their caching.\n */\n title: 'Use efficient cache lifetimes',\n /**\n * @description Text to tell the user about how caching can help improve performance.\n */\n description:\n 'A long cache lifetime can speed up repeat visits to your page. [Learn more](https://web.dev/uses-long-cache-ttl/).',\n /**\n * @description Column for a font loaded by the page to render text.\n */\n requestColumn: 'Request',\n /**\n * @description Column for a resource cache's Time To Live.\n */\n cacheTTL: 'Cache TTL',\n /**\n * @description Text describing that there were no requests found that need caching.\n */\n noRequestsToCache: 'No requests with inefficient cache policies',\n /**\n * @description Table row value representing the remaining items not shown in the table due to size constraints. This row will always represent at least 2 items.\n * @example {5} PH1\n */\n others: '{PH1} others',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/Cache.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type CacheInsightModel = InsightModel<typeof UIStrings, {\n requests: Array<{\n request: Types.Events.SyntheticNetworkRequest,\n ttl: number,\n wastedBytes: number,\n }>,\n}>;\n\n// Threshold for cache hits.\nconst IGNORE_THRESHOLD_IN_PERCENT = 0.925;\n\nfunction finalize(partialModel: PartialInsightModel<CacheInsightModel>): CacheInsightModel {\n return {\n insightKey: InsightKeys.CACHE,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.ALL,\n state: partialModel.requests.length > 0 ? 'fail' : 'pass',\n ...partialModel,\n };\n}\n\n/**\n * Determines if a request is \"cacheable\".\n * A request is \"cacheable\" if it is of the appropriate protocol and resource type\n * (see Helpers.Network.NON_NETWORK_SCHEMES and Helpers.Network.STATIC_RESOURCE_TYPE)\n * and has the appropriate statusCodes.\n */\nexport function isCacheable(request: Types.Events.SyntheticNetworkRequest): boolean {\n // Caching doesn't make sense for requests not loaded over the network.\n if (Helpers.Network.NON_NETWORK_SCHEMES.includes(request.args.data.protocol)) {\n return false;\n }\n return Boolean(\n Helpers.Network.CACHEABLE_STATUS_CODES.has(request.args.data.statusCode) &&\n Helpers.Network.STATIC_RESOURCE_TYPES.has(request.args.data.resourceType || Protocol.Network.ResourceType.Other));\n}\n\n/**\n * Returns max-age if defined, otherwise expires header if defined, and null if not.\n */\nexport function computeCacheLifetimeInSeconds(\n headers: Array<{name: string, value: string}>, cacheControl: Helpers.Network.CacheControl|null): number|null {\n if (cacheControl?.['max-age'] !== undefined) {\n return cacheControl['max-age'];\n }\n\n const expiresHeaders = headers.find(h => h.name === 'expires')?.value ?? null;\n if (expiresHeaders) {\n const expires = new Date(expiresHeaders).getTime();\n // Treat expires values as having already expired.\n if (!expires) {\n return 0;\n }\n return Math.ceil((expires - Date.now()) / 1000);\n }\n return null;\n}\n\n/**\n * Computes the percent likelihood that a return visit will be within the cache lifetime, based on\n * historical Chrome UMA stats (see RESOURCE_AGE_IN_HOURS_DECILES comment).\n *\n * This function returns values on this curve: https://www.desmos.com/calculator/eaqiszhugy (but using seconds, rather than hours)\n * See http://github.com/GoogleChrome/lighthouse/pull/3531 for history.\n */\nfunction getCacheHitProbability(maxAgeInSeconds: number): number {\n // This array contains the hand wavy distribution of the age of a resource in hours at the time of\n // cache hit at 0th, 10th, 20th, 30th, etc percentiles. This is used to compute `wastedMs` since there\n // are clearly diminishing returns to cache duration i.e. 6 months is not 2x better than 3 months.\n // Based on UMA stats for HttpCache.StaleEntry.Validated.Age. see https://www.desmos.com/calculator/jjwc5mzuwd\n // This UMA data is from 2017 but the metric isn't tracked any longer in 2025.\n const RESOURCE_AGE_IN_HOURS_DECILES = [0, 0.2, 1, 3, 8, 12, 24, 48, 72, 168, 8760, Infinity];\n\n const maxAgeInHours = maxAgeInSeconds / 3600;\n const upperDecileIndex = RESOURCE_AGE_IN_HOURS_DECILES.findIndex(decile => decile >= maxAgeInHours);\n\n // Clip the likelihood between 0 and 1\n if (upperDecileIndex === RESOURCE_AGE_IN_HOURS_DECILES.length - 1) {\n return 1;\n }\n if (upperDecileIndex === 0) {\n return 0;\n }\n\n // Use the two closest decile points as control points\n const upperDecileValue = RESOURCE_AGE_IN_HOURS_DECILES[upperDecileIndex];\n const lowerDecileValue = RESOURCE_AGE_IN_HOURS_DECILES[upperDecileIndex - 1];\n const upperDecile = upperDecileIndex / 10;\n const lowerDecile = (upperDecileIndex - 1) / 10;\n\n // Approximate the real likelihood with linear interpolation\n return linearInterpolation(lowerDecileValue, lowerDecile, upperDecileValue, upperDecile, maxAgeInHours);\n}\n\nexport function getCombinedHeaders(responseHeaders: Array<{name: string, value: string}>): Map<string, string> {\n const headers = new Map<string, string>();\n for (const header of responseHeaders) {\n const name = header.name.toLowerCase();\n if (headers.get(name)) {\n headers.set(name, `${headers.get(name)}, ${header.value}`);\n } else {\n headers.set(name, header.value);\n }\n }\n return headers;\n}\n\n/**\n * Returns whether a request contains headers that disable caching.\n * Disabled caching is checked on the 'cache-control' and 'pragma' headers.\n */\nexport function cachingDisabled(\n headers: Map<string, string>|null, parsedCacheControl: Helpers.Network.CacheControl|null): boolean {\n const cacheControl = headers?.get('cache-control') ?? null;\n const pragma = headers?.get('pragma') ?? null;\n\n // The HTTP/1.0 Pragma header can disable caching if cache-control is not set, see https://tools.ietf.org/html/rfc7234#section-5.4\n if (!cacheControl && pragma?.includes('no-cache')) {\n return true;\n }\n\n // If we have any of these, the user intentionally doesn't want to cache.\n if (parsedCacheControl &&\n (parsedCacheControl['must-revalidate'] || parsedCacheControl['no-cache'] || parsedCacheControl['no-store'] ||\n parsedCacheControl['private'])) {\n return true;\n }\n\n return false;\n}\n\nexport interface CacheableRequest {\n request: Types.Events.SyntheticNetworkRequest;\n ttl: number;\n wastedBytes: number;\n}\n\nexport function isCacheInsight(model: InsightModel): model is CacheInsightModel {\n return model.insightKey === InsightKeys.CACHE;\n}\n\nexport function generateInsight(data: Handlers.Types.HandlerData, context: InsightSetContext): CacheInsightModel {\n const isWithinContext = (event: Types.Events.Event): boolean => Helpers.Timing.eventIsInBounds(event, context.bounds);\n const contextRequests = data.NetworkRequests.byTime.filter(isWithinContext);\n\n const results: CacheableRequest[] = [];\n let totalWastedBytes = 0;\n const wastedBytesByRequestId = new Map<string, number>();\n for (const req of contextRequests) {\n if (!req.args.data.responseHeaders || !isCacheable(req)) {\n continue;\n }\n\n const headers = getCombinedHeaders(req.args.data.responseHeaders);\n const cacheControl = headers.get('cache-control') ?? null;\n const parsedDirectives = Helpers.Network.parseCacheControl(cacheControl);\n\n // Skip requests that are deliberately avoiding caching.\n if (cachingDisabled(headers, parsedDirectives)) {\n continue;\n }\n\n let ttl = computeCacheLifetimeInSeconds(req.args.data.responseHeaders, parsedDirectives);\n // Ignore if a non-positive number.\n if (ttl !== null && (!Number.isFinite(ttl) || ttl <= 0)) {\n continue;\n }\n ttl = ttl || 0;\n\n // Ignore >= 30d.\n const ttlDays = ttl / 86400;\n if (ttlDays >= 30) {\n continue;\n }\n\n // If cache lifetime is high enough, let's skip.\n const cacheHitProbability = getCacheHitProbability(ttl);\n if (cacheHitProbability > IGNORE_THRESHOLD_IN_PERCENT) {\n continue;\n }\n\n const transferSize = req.args.data.encodedDataLength || 0;\n const wastedBytes = (1 - cacheHitProbability) * transferSize;\n\n wastedBytesByRequestId.set(req.args.data.requestId, wastedBytes);\n totalWastedBytes += wastedBytes;\n\n results.push({request: req, ttl, wastedBytes});\n }\n\n // Sort by transfer size.\n results.sort((a, b) => {\n return b.request.args.data.decodedBodyLength - a.request.args.data.decodedBodyLength || a.ttl - b.ttl;\n });\n\n return finalize({\n relatedEvents: results.map(r => r.request),\n requests: results,\n metricSavings: metricSavingsForWastedBytes(wastedBytesByRequestId, context),\n wastedBytes: totalWastedBytes,\n });\n}\n\nexport function createOverlayForRequest(request: Types.Events.SyntheticNetworkRequest): Types.Overlays.EntryOutline {\n return {\n type: 'ENTRY_OUTLINE',\n entry: request,\n outlineReason: 'ERROR',\n };\n}\n\nexport function createOverlays(model: CacheInsightModel): Types.Overlays.Overlay[] {\n return model.requests.map(req => createOverlayForRequest(req.request));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Cache.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/Cache.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2025 The Chromium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Protocol from '../../../generated/protocol.js';\nimport type * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Types from '../types/types.js';\n\nimport {metricSavingsForWastedBytes} from './Common.js';\nimport {linearInterpolation} from './Statistics.js';\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /**\n * @description Title of an insight that provides information and suggestions of resources that could improve their caching.\n */\n title: 'Use efficient cache lifetimes',\n /**\n * @description Text to tell the user about how caching can help improve performance.\n */\n description:\n 'A long cache lifetime can speed up repeat visits to your page. [Learn more about caching](https://developer.chrome.com/docs/performance/insights/cache).',\n /**\n * @description Column for a font loaded by the page to render text.\n */\n requestColumn: 'Request',\n /**\n * @description Column for a resource cache's Time To Live.\n */\n cacheTTL: 'Cache TTL',\n /**\n * @description Text describing that there were no requests found that need caching.\n */\n noRequestsToCache: 'No requests with inefficient cache policies',\n /**\n * @description Table row value representing the remaining items not shown in the table due to size constraints. This row will always represent at least 2 items.\n * @example {5} PH1\n */\n others: '{PH1} others',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/Cache.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nexport type CacheInsightModel = InsightModel<typeof UIStrings, {\n requests: Array<{\n request: Types.Events.SyntheticNetworkRequest,\n ttl: number,\n wastedBytes: number,\n }>,\n}>;\n\n// Threshold for cache hits.\nconst IGNORE_THRESHOLD_IN_PERCENT = 0.925;\n\nfunction finalize(partialModel: PartialInsightModel<CacheInsightModel>): CacheInsightModel {\n return {\n insightKey: InsightKeys.CACHE,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n docs: 'https://developer.chrome.com/docs/performance/insights/cache',\n category: InsightCategory.ALL,\n state: partialModel.requests.length > 0 ? 'fail' : 'pass',\n ...partialModel,\n };\n}\n\n/**\n * Determines if a request is \"cacheable\".\n * A request is \"cacheable\" if it is of the appropriate protocol and resource type\n * (see Helpers.Network.NON_NETWORK_SCHEMES and Helpers.Network.STATIC_RESOURCE_TYPE)\n * and has the appropriate statusCodes.\n */\nexport function isCacheable(request: Types.Events.SyntheticNetworkRequest): boolean {\n // Caching doesn't make sense for requests not loaded over the network.\n if (Helpers.Network.NON_NETWORK_SCHEMES.includes(request.args.data.protocol)) {\n return false;\n }\n return Boolean(\n Helpers.Network.CACHEABLE_STATUS_CODES.has(request.args.data.statusCode) &&\n Helpers.Network.STATIC_RESOURCE_TYPES.has(request.args.data.resourceType || Protocol.Network.ResourceType.Other));\n}\n\n/**\n * Returns max-age if defined, otherwise expires header if defined, and null if not.\n */\nexport function computeCacheLifetimeInSeconds(\n headers: Array<{name: string, value: string}>, cacheControl: Helpers.Network.CacheControl|null): number|null {\n if (cacheControl?.['max-age'] !== undefined) {\n return cacheControl['max-age'];\n }\n\n const expiresHeaders = headers.find(h => h.name === 'expires')?.value ?? null;\n if (expiresHeaders) {\n const expires = new Date(expiresHeaders).getTime();\n // Treat expires values as having already expired.\n if (!expires) {\n return 0;\n }\n return Math.ceil((expires - Date.now()) / 1000);\n }\n return null;\n}\n\n/**\n * Computes the percent likelihood that a return visit will be within the cache lifetime, based on\n * historical Chrome UMA stats (see RESOURCE_AGE_IN_HOURS_DECILES comment).\n *\n * This function returns values on this curve: https://www.desmos.com/calculator/eaqiszhugy (but using seconds, rather than hours)\n * See http://github.com/GoogleChrome/lighthouse/pull/3531 for history.\n */\nfunction getCacheHitProbability(maxAgeInSeconds: number): number {\n // This array contains the hand wavy distribution of the age of a resource in hours at the time of\n // cache hit at 0th, 10th, 20th, 30th, etc percentiles. This is used to compute `wastedMs` since there\n // are clearly diminishing returns to cache duration i.e. 6 months is not 2x better than 3 months.\n // Based on UMA stats for HttpCache.StaleEntry.Validated.Age. see https://www.desmos.com/calculator/jjwc5mzuwd\n // This UMA data is from 2017 but the metric isn't tracked any longer in 2025.\n const RESOURCE_AGE_IN_HOURS_DECILES = [0, 0.2, 1, 3, 8, 12, 24, 48, 72, 168, 8760, Infinity];\n\n const maxAgeInHours = maxAgeInSeconds / 3600;\n const upperDecileIndex = RESOURCE_AGE_IN_HOURS_DECILES.findIndex(decile => decile >= maxAgeInHours);\n\n // Clip the likelihood between 0 and 1\n if (upperDecileIndex === RESOURCE_AGE_IN_HOURS_DECILES.length - 1) {\n return 1;\n }\n if (upperDecileIndex === 0) {\n return 0;\n }\n\n // Use the two closest decile points as control points\n const upperDecileValue = RESOURCE_AGE_IN_HOURS_DECILES[upperDecileIndex];\n const lowerDecileValue = RESOURCE_AGE_IN_HOURS_DECILES[upperDecileIndex - 1];\n const upperDecile = upperDecileIndex / 10;\n const lowerDecile = (upperDecileIndex - 1) / 10;\n\n // Approximate the real likelihood with linear interpolation\n return linearInterpolation(lowerDecileValue, lowerDecile, upperDecileValue, upperDecile, maxAgeInHours);\n}\n\nexport function getCombinedHeaders(responseHeaders: Array<{name: string, value: string}>): Map<string, string> {\n const headers = new Map<string, string>();\n for (const header of responseHeaders) {\n const name = header.name.toLowerCase();\n if (headers.get(name)) {\n headers.set(name, `${headers.get(name)}, ${header.value}`);\n } else {\n headers.set(name, header.value);\n }\n }\n return headers;\n}\n\n/**\n * Returns whether a request contains headers that disable caching.\n * Disabled caching is checked on the 'cache-control' and 'pragma' headers.\n */\nexport function cachingDisabled(\n headers: Map<string, string>|null, parsedCacheControl: Helpers.Network.CacheControl|null): boolean {\n const cacheControl = headers?.get('cache-control') ?? null;\n const pragma = headers?.get('pragma') ?? null;\n\n // The HTTP/1.0 Pragma header can disable caching if cache-control is not set, see https://tools.ietf.org/html/rfc7234#section-5.4\n if (!cacheControl && pragma?.includes('no-cache')) {\n return true;\n }\n\n // If we have any of these, the user intentionally doesn't want to cache.\n if (parsedCacheControl &&\n (parsedCacheControl['must-revalidate'] || parsedCacheControl['no-cache'] || parsedCacheControl['no-store'] ||\n parsedCacheControl['private'])) {\n return true;\n }\n\n return false;\n}\n\nexport interface CacheableRequest {\n request: Types.Events.SyntheticNetworkRequest;\n ttl: number;\n wastedBytes: number;\n}\n\nexport function isCacheInsight(model: InsightModel): model is CacheInsightModel {\n return model.insightKey === InsightKeys.CACHE;\n}\n\nexport function generateInsight(data: Handlers.Types.HandlerData, context: InsightSetContext): CacheInsightModel {\n const isWithinContext = (event: Types.Events.Event): boolean => Helpers.Timing.eventIsInBounds(event, context.bounds);\n const contextRequests = data.NetworkRequests.byTime.filter(isWithinContext);\n\n const results: CacheableRequest[] = [];\n let totalWastedBytes = 0;\n const wastedBytesByRequestId = new Map<string, number>();\n for (const req of contextRequests) {\n if (!req.args.data.responseHeaders || !isCacheable(req)) {\n continue;\n }\n\n const headers = getCombinedHeaders(req.args.data.responseHeaders);\n const cacheControl = headers.get('cache-control') ?? null;\n const parsedDirectives = Helpers.Network.parseCacheControl(cacheControl);\n\n // Skip requests that are deliberately avoiding caching.\n if (cachingDisabled(headers, parsedDirectives)) {\n continue;\n }\n\n let ttl = computeCacheLifetimeInSeconds(req.args.data.responseHeaders, parsedDirectives);\n // Ignore if a non-positive number.\n if (ttl !== null && (!Number.isFinite(ttl) || ttl <= 0)) {\n continue;\n }\n ttl = ttl || 0;\n\n // Ignore >= 30d.\n const ttlDays = ttl / 86400;\n if (ttlDays >= 30) {\n continue;\n }\n\n // If cache lifetime is high enough, let's skip.\n const cacheHitProbability = getCacheHitProbability(ttl);\n if (cacheHitProbability > IGNORE_THRESHOLD_IN_PERCENT) {\n continue;\n }\n\n const transferSize = req.args.data.encodedDataLength || 0;\n const wastedBytes = (1 - cacheHitProbability) * transferSize;\n\n wastedBytesByRequestId.set(req.args.data.requestId, wastedBytes);\n totalWastedBytes += wastedBytes;\n\n results.push({request: req, ttl, wastedBytes});\n }\n\n // Sort by transfer size.\n results.sort((a, b) => {\n return b.request.args.data.decodedBodyLength - a.request.args.data.decodedBodyLength || a.ttl - b.ttl;\n });\n\n return finalize({\n relatedEvents: results.map(r => r.request),\n requests: results,\n metricSavings: metricSavingsForWastedBytes(wastedBytesByRequestId, context),\n wastedBytes: totalWastedBytes,\n });\n}\n\nexport function createOverlayForRequest(request: Types.Events.SyntheticNetworkRequest): Types.Overlays.EntryOutline {\n return {\n type: 'ENTRY_OUTLINE',\n entry: request,\n outlineReason: 'ERROR',\n };\n}\n\nexport function createOverlays(model: CacheInsightModel): Types.Overlays.Overlay[] {\n return model.requests.map(req => createOverlayForRequest(req.request));\n}\n"]}
|
|
@@ -10,7 +10,7 @@ export declare const UIStrings: {
|
|
|
10
10
|
/**
|
|
11
11
|
* @description Description of an insight that recommends reducing the size of the DOM tree as a means to improve page responsiveness. "DOM" is an acronym and should not be translated. "layout reflows" are when the browser will recompute the layout of content on the page.
|
|
12
12
|
*/
|
|
13
|
-
readonly description: "A large DOM can increase the duration of style calculations and layout reflows, impacting page responsiveness. A large DOM will also increase memory usage. [Learn how to avoid an excessive DOM size](https://developer.chrome.com/docs/
|
|
13
|
+
readonly description: "A large DOM can increase the duration of style calculations and layout reflows, impacting page responsiveness. A large DOM will also increase memory usage. [Learn how to avoid an excessive DOM size](https://developer.chrome.com/docs/performance/insights/dom-size).";
|
|
14
14
|
/**
|
|
15
15
|
* @description Header for a column containing the names of statistics as opposed to the actual statistic values.
|
|
16
16
|
*/
|
|
@@ -14,7 +14,7 @@ export const UIStrings = {
|
|
|
14
14
|
/**
|
|
15
15
|
* @description Description of an insight that recommends reducing the size of the DOM tree as a means to improve page responsiveness. "DOM" is an acronym and should not be translated. "layout reflows" are when the browser will recompute the layout of content on the page.
|
|
16
16
|
*/
|
|
17
|
-
description: 'A large DOM can increase the duration of style calculations and layout reflows, impacting page responsiveness. A large DOM will also increase memory usage. [Learn how to avoid an excessive DOM size](https://developer.chrome.com/docs/
|
|
17
|
+
description: 'A large DOM can increase the duration of style calculations and layout reflows, impacting page responsiveness. A large DOM will also increase memory usage. [Learn how to avoid an excessive DOM size](https://developer.chrome.com/docs/performance/insights/dom-size).',
|
|
18
18
|
/**
|
|
19
19
|
* @description Header for a column containing the names of statistics as opposed to the actual statistic values.
|
|
20
20
|
*/
|
|
@@ -73,6 +73,7 @@ function finalize(partialModel) {
|
|
|
73
73
|
strings: UIStrings,
|
|
74
74
|
title: i18nString(UIStrings.title),
|
|
75
75
|
description: i18nString(UIStrings.description),
|
|
76
|
+
docs: 'https://developer.chrome.com/docs/performance/insights/dom-size',
|
|
76
77
|
category: InsightCategory.INP,
|
|
77
78
|
state: relatedEvents.length > 0 ? 'informative' : 'pass',
|
|
78
79
|
...partialModel,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DOMSize.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/DOMSize.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Common from '../../../core/common/common.js';\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /**\n * @description Title of an insight that recommends reducing the size of the DOM tree as a means to improve page responsiveness. \"DOM\" is an acronym and should not be translated.\n */\n title: 'Optimize DOM size',\n /**\n * @description Description of an insight that recommends reducing the size of the DOM tree as a means to improve page responsiveness. \"DOM\" is an acronym and should not be translated. \"layout reflows\" are when the browser will recompute the layout of content on the page.\n */\n description:\n 'A large DOM can increase the duration of style calculations and layout reflows, impacting page responsiveness. A large DOM will also increase memory usage. [Learn how to avoid an excessive DOM size](https://developer.chrome.com/docs/lighthouse/performance/dom-size/).',\n /**\n * @description Header for a column containing the names of statistics as opposed to the actual statistic values.\n */\n statistic: 'Statistic',\n /**\n * @description Header for a column containing the value of a statistic.\n */\n value: 'Value',\n /**\n * @description Header for a column containing the page element related to a statistic.\n */\n element: 'Element',\n /**\n * @description Label for a value representing the total number of elements on the page.\n */\n totalElements: 'Total elements',\n /**\n * @description Label for a value representing the maximum depth of the Document Object Model (DOM). \"DOM\" is a acronym and should not be translated.\n */\n maxDOMDepth: 'DOM depth',\n /**\n * @description Label for a value representing the maximum number of child elements of any parent element on the page.\n */\n maxChildren: 'Most children',\n /**\n * @description Text for a section.\n */\n topUpdatesDescription:\n 'These are the largest layout and style recalculation events. Their performance impact may be reduced by making the DOM simpler.',\n /**\n * @description Label used for a time duration.\n */\n duration: 'Duration',\n /**\n * @description Message displayed in a table detailing how big a layout (rendering) is.\n * @example {134} PH1\n */\n largeLayout: 'Layout ({PH1} objects)',\n /**\n * @description Message displayed in a table detailing how big a style recalculation (rendering) is.\n * @example {134} PH1\n */\n largeStyleRecalc: 'Style recalculation ({PH1} elements)',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/DOMSize.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nconst DOM_SIZE_DURATION_THRESHOLD = Helpers.Timing.milliToMicro(Types.Timing.Milli(40));\n\n// These thresholds were selected to maximize the number of long (>40ms) events above\n// the threshold while maximizing the number of short (<40ms) events below the threshold.\n// See go/rpp-dom-size-thresholds for the analysis that produced these thresholds.\nconst LAYOUT_OBJECTS_THRESHOLD = 100;\nconst STYLE_RECALC_ELEMENTS_THRESHOLD = 300;\n\nexport type DOMSizeInsightModel = InsightModel<typeof UIStrings, {\n largeLayoutUpdates: Types.Events.Layout[],\n largeStyleRecalcs: Types.Events.RecalcStyle[],\n largeUpdates: Array<\n {label: Common.UIString.LocalizedString, duration: Types.Timing.Milli, size: number, event: Types.Events.Event}>,\n maxDOMStats?: Types.Events.DOMStats,\n}>;\n\nfunction finalize(partialModel: PartialInsightModel<DOMSizeInsightModel>): DOMSizeInsightModel {\n const relatedEvents = [...partialModel.largeLayoutUpdates, ...partialModel.largeStyleRecalcs];\n return {\n insightKey: InsightKeys.DOM_SIZE,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n category: InsightCategory.INP,\n state: relatedEvents.length > 0 ? 'informative' : 'pass',\n ...partialModel,\n relatedEvents,\n };\n}\n\nexport function isDomSizeInsight(model: InsightModel): model is DOMSizeInsightModel {\n return model.insightKey === InsightKeys.DOM_SIZE;\n}\n\nexport function generateInsight(data: Handlers.Types.HandlerData, context: InsightSetContext): DOMSizeInsightModel {\n const isWithinContext = (event: Types.Events.Event): boolean => Helpers.Timing.eventIsInBounds(event, context.bounds);\n\n const mainTid = context.navigation?.tid;\n\n const largeLayoutUpdates: Types.Events.Layout[] = [];\n const largeStyleRecalcs: Types.Events.RecalcStyle[] = [];\n\n const threads = Handlers.Threads.threadsInRenderer(data.Renderer, data.AuctionWorklets);\n for (const thread of threads) {\n if (thread.type !== Handlers.Threads.ThreadType.MAIN_THREAD) {\n continue;\n }\n\n if (mainTid === undefined) {\n // We won't have a specific thread ID to reference if the context does not have a navigation.\n // In this case, we'll just filter out any OOPIFs threads.\n if (!thread.processIsOnMainFrame) {\n continue;\n }\n } else if (thread.tid !== mainTid) {\n continue;\n }\n\n const rendererThread = data.Renderer.processes.get(thread.pid)?.threads.get(thread.tid);\n if (!rendererThread) {\n continue;\n }\n\n const {entries, layoutEvents, recalcStyleEvents} = rendererThread;\n if (!entries.length) {\n continue;\n }\n\n const first = entries[0];\n const last = entries[entries.length - 1];\n const timeRange =\n Helpers.Timing.traceWindowFromMicroSeconds(first.ts, Types.Timing.Micro(last.ts + (last.dur ?? 0)));\n if (!Helpers.Timing.boundsIncludeTimeRange({timeRange, bounds: context.bounds})) {\n continue;\n }\n\n for (const event of layoutEvents) {\n if (event.dur < DOM_SIZE_DURATION_THRESHOLD || !isWithinContext(event)) {\n continue;\n }\n\n const {dirtyObjects} = event.args.beginData;\n if (dirtyObjects > LAYOUT_OBJECTS_THRESHOLD) {\n largeLayoutUpdates.push(event);\n }\n }\n\n for (const event of recalcStyleEvents) {\n if (event.dur < DOM_SIZE_DURATION_THRESHOLD || !isWithinContext(event)) {\n continue;\n }\n\n const {elementCount} = event.args;\n if (elementCount > STYLE_RECALC_ELEMENTS_THRESHOLD) {\n largeStyleRecalcs.push(event);\n }\n }\n }\n\n const largeUpdates: DOMSizeInsightModel['largeUpdates'] = [\n ...largeLayoutUpdates.map(event => {\n const duration = (event.dur / 1000) as Types.Timing.Milli;\n const size = event.args.beginData.dirtyObjects;\n const label = i18nString(UIStrings.largeLayout, {PH1: size});\n return {label, duration, size, event};\n }),\n ...largeStyleRecalcs.map(event => {\n const duration = (event.dur / 1000) as Types.Timing.Milli;\n const size = event.args.elementCount;\n const label = i18nString(UIStrings.largeStyleRecalc, {PH1: size});\n return {label, duration, size, event};\n }),\n ].sort((a, b) => b.duration - a.duration).slice(0, 5);\n\n const domStatsEvents = data.DOMStats.domStatsByFrameId.get(context.frameId)?.filter(isWithinContext) ?? [];\n let maxDOMStats: Types.Events.DOMStats|undefined;\n for (const domStats of domStatsEvents) {\n // While recording a cross-origin navigation, there can be overlapping dom stats from before & after\n // the navigation which share a frameId. In this case we should also ensure the pid matches up with\n // the navigation we care about (i.e. from after the navigation event).\n const navigationPid = context.navigation?.pid;\n if (navigationPid && domStats.pid !== navigationPid) {\n continue;\n }\n\n if (!maxDOMStats || domStats.args.data.totalElements > maxDOMStats.args.data.totalElements) {\n maxDOMStats = domStats;\n }\n }\n\n return finalize({\n largeLayoutUpdates,\n largeStyleRecalcs,\n largeUpdates,\n maxDOMStats,\n });\n}\n\nexport function createOverlays(model: DOMSizeInsightModel): Types.Overlays.Overlay[] {\n const entries = [...model.largeStyleRecalcs, ...model.largeLayoutUpdates];\n return entries.map(entry => ({\n type: 'ENTRY_OUTLINE',\n entry,\n outlineReason: 'ERROR',\n }));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"DOMSize.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/DOMSize.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nimport type * as Common from '../../../core/common/common.js';\nimport * as i18n from '../../../core/i18n/i18n.js';\nimport * as Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {\n InsightCategory,\n InsightKeys,\n type InsightModel,\n type InsightSetContext,\n type PartialInsightModel,\n} from './types.js';\n\nexport const UIStrings = {\n /**\n * @description Title of an insight that recommends reducing the size of the DOM tree as a means to improve page responsiveness. \"DOM\" is an acronym and should not be translated.\n */\n title: 'Optimize DOM size',\n /**\n * @description Description of an insight that recommends reducing the size of the DOM tree as a means to improve page responsiveness. \"DOM\" is an acronym and should not be translated. \"layout reflows\" are when the browser will recompute the layout of content on the page.\n */\n description:\n 'A large DOM can increase the duration of style calculations and layout reflows, impacting page responsiveness. A large DOM will also increase memory usage. [Learn how to avoid an excessive DOM size](https://developer.chrome.com/docs/performance/insights/dom-size).',\n /**\n * @description Header for a column containing the names of statistics as opposed to the actual statistic values.\n */\n statistic: 'Statistic',\n /**\n * @description Header for a column containing the value of a statistic.\n */\n value: 'Value',\n /**\n * @description Header for a column containing the page element related to a statistic.\n */\n element: 'Element',\n /**\n * @description Label for a value representing the total number of elements on the page.\n */\n totalElements: 'Total elements',\n /**\n * @description Label for a value representing the maximum depth of the Document Object Model (DOM). \"DOM\" is a acronym and should not be translated.\n */\n maxDOMDepth: 'DOM depth',\n /**\n * @description Label for a value representing the maximum number of child elements of any parent element on the page.\n */\n maxChildren: 'Most children',\n /**\n * @description Text for a section.\n */\n topUpdatesDescription:\n 'These are the largest layout and style recalculation events. Their performance impact may be reduced by making the DOM simpler.',\n /**\n * @description Label used for a time duration.\n */\n duration: 'Duration',\n /**\n * @description Message displayed in a table detailing how big a layout (rendering) is.\n * @example {134} PH1\n */\n largeLayout: 'Layout ({PH1} objects)',\n /**\n * @description Message displayed in a table detailing how big a style recalculation (rendering) is.\n * @example {134} PH1\n */\n largeStyleRecalc: 'Style recalculation ({PH1} elements)',\n} as const;\n\nconst str_ = i18n.i18n.registerUIStrings('models/trace/insights/DOMSize.ts', UIStrings);\nexport const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);\n\nconst DOM_SIZE_DURATION_THRESHOLD = Helpers.Timing.milliToMicro(Types.Timing.Milli(40));\n\n// These thresholds were selected to maximize the number of long (>40ms) events above\n// the threshold while maximizing the number of short (<40ms) events below the threshold.\n// See go/rpp-dom-size-thresholds for the analysis that produced these thresholds.\nconst LAYOUT_OBJECTS_THRESHOLD = 100;\nconst STYLE_RECALC_ELEMENTS_THRESHOLD = 300;\n\nexport type DOMSizeInsightModel = InsightModel<typeof UIStrings, {\n largeLayoutUpdates: Types.Events.Layout[],\n largeStyleRecalcs: Types.Events.RecalcStyle[],\n largeUpdates: Array<\n {label: Common.UIString.LocalizedString, duration: Types.Timing.Milli, size: number, event: Types.Events.Event}>,\n maxDOMStats?: Types.Events.DOMStats,\n}>;\n\nfunction finalize(partialModel: PartialInsightModel<DOMSizeInsightModel>): DOMSizeInsightModel {\n const relatedEvents = [...partialModel.largeLayoutUpdates, ...partialModel.largeStyleRecalcs];\n return {\n insightKey: InsightKeys.DOM_SIZE,\n strings: UIStrings,\n title: i18nString(UIStrings.title),\n description: i18nString(UIStrings.description),\n docs: 'https://developer.chrome.com/docs/performance/insights/dom-size',\n category: InsightCategory.INP,\n state: relatedEvents.length > 0 ? 'informative' : 'pass',\n ...partialModel,\n relatedEvents,\n };\n}\n\nexport function isDomSizeInsight(model: InsightModel): model is DOMSizeInsightModel {\n return model.insightKey === InsightKeys.DOM_SIZE;\n}\n\nexport function generateInsight(data: Handlers.Types.HandlerData, context: InsightSetContext): DOMSizeInsightModel {\n const isWithinContext = (event: Types.Events.Event): boolean => Helpers.Timing.eventIsInBounds(event, context.bounds);\n\n const mainTid = context.navigation?.tid;\n\n const largeLayoutUpdates: Types.Events.Layout[] = [];\n const largeStyleRecalcs: Types.Events.RecalcStyle[] = [];\n\n const threads = Handlers.Threads.threadsInRenderer(data.Renderer, data.AuctionWorklets);\n for (const thread of threads) {\n if (thread.type !== Handlers.Threads.ThreadType.MAIN_THREAD) {\n continue;\n }\n\n if (mainTid === undefined) {\n // We won't have a specific thread ID to reference if the context does not have a navigation.\n // In this case, we'll just filter out any OOPIFs threads.\n if (!thread.processIsOnMainFrame) {\n continue;\n }\n } else if (thread.tid !== mainTid) {\n continue;\n }\n\n const rendererThread = data.Renderer.processes.get(thread.pid)?.threads.get(thread.tid);\n if (!rendererThread) {\n continue;\n }\n\n const {entries, layoutEvents, recalcStyleEvents} = rendererThread;\n if (!entries.length) {\n continue;\n }\n\n const first = entries[0];\n const last = entries[entries.length - 1];\n const timeRange =\n Helpers.Timing.traceWindowFromMicroSeconds(first.ts, Types.Timing.Micro(last.ts + (last.dur ?? 0)));\n if (!Helpers.Timing.boundsIncludeTimeRange({timeRange, bounds: context.bounds})) {\n continue;\n }\n\n for (const event of layoutEvents) {\n if (event.dur < DOM_SIZE_DURATION_THRESHOLD || !isWithinContext(event)) {\n continue;\n }\n\n const {dirtyObjects} = event.args.beginData;\n if (dirtyObjects > LAYOUT_OBJECTS_THRESHOLD) {\n largeLayoutUpdates.push(event);\n }\n }\n\n for (const event of recalcStyleEvents) {\n if (event.dur < DOM_SIZE_DURATION_THRESHOLD || !isWithinContext(event)) {\n continue;\n }\n\n const {elementCount} = event.args;\n if (elementCount > STYLE_RECALC_ELEMENTS_THRESHOLD) {\n largeStyleRecalcs.push(event);\n }\n }\n }\n\n const largeUpdates: DOMSizeInsightModel['largeUpdates'] = [\n ...largeLayoutUpdates.map(event => {\n const duration = (event.dur / 1000) as Types.Timing.Milli;\n const size = event.args.beginData.dirtyObjects;\n const label = i18nString(UIStrings.largeLayout, {PH1: size});\n return {label, duration, size, event};\n }),\n ...largeStyleRecalcs.map(event => {\n const duration = (event.dur / 1000) as Types.Timing.Milli;\n const size = event.args.elementCount;\n const label = i18nString(UIStrings.largeStyleRecalc, {PH1: size});\n return {label, duration, size, event};\n }),\n ].sort((a, b) => b.duration - a.duration).slice(0, 5);\n\n const domStatsEvents = data.DOMStats.domStatsByFrameId.get(context.frameId)?.filter(isWithinContext) ?? [];\n let maxDOMStats: Types.Events.DOMStats|undefined;\n for (const domStats of domStatsEvents) {\n // While recording a cross-origin navigation, there can be overlapping dom stats from before & after\n // the navigation which share a frameId. In this case we should also ensure the pid matches up with\n // the navigation we care about (i.e. from after the navigation event).\n const navigationPid = context.navigation?.pid;\n if (navigationPid && domStats.pid !== navigationPid) {\n continue;\n }\n\n if (!maxDOMStats || domStats.args.data.totalElements > maxDOMStats.args.data.totalElements) {\n maxDOMStats = domStats;\n }\n }\n\n return finalize({\n largeLayoutUpdates,\n largeStyleRecalcs,\n largeUpdates,\n maxDOMStats,\n });\n}\n\nexport function createOverlays(model: DOMSizeInsightModel): Types.Overlays.Overlay[] {\n const entries = [...model.largeStyleRecalcs, ...model.largeLayoutUpdates];\n return entries.map(entry => ({\n type: 'ENTRY_OUTLINE',\n entry,\n outlineReason: 'ERROR',\n }));\n}\n"]}
|
|
@@ -9,7 +9,7 @@ export declare const UIStrings: {
|
|
|
9
9
|
/**
|
|
10
10
|
* @description Description of an insight that provides a breakdown for how long it took to download the main document.
|
|
11
11
|
*/
|
|
12
|
-
readonly description: "Your first network request is the most important.
|
|
12
|
+
readonly description: "Your first network request is the most important. [Reduce its latency](https://developer.chrome.com/docs/performance/insights/document-latency) by avoiding redirects, ensuring a fast server response, and enabling text compression.";
|
|
13
13
|
/**
|
|
14
14
|
* @description Text to tell the user that the document request does not have redirects.
|
|
15
15
|
*/
|
|
@@ -14,7 +14,7 @@ export const UIStrings = {
|
|
|
14
14
|
/**
|
|
15
15
|
* @description Description of an insight that provides a breakdown for how long it took to download the main document.
|
|
16
16
|
*/
|
|
17
|
-
description: 'Your first network request is the most important.
|
|
17
|
+
description: 'Your first network request is the most important. [Reduce its latency](https://developer.chrome.com/docs/performance/insights/document-latency) by avoiding redirects, ensuring a fast server response, and enabling text compression.',
|
|
18
18
|
/**
|
|
19
19
|
* @description Text to tell the user that the document request does not have redirects.
|
|
20
20
|
*/
|
|
@@ -148,6 +148,7 @@ function finalize(partialModel) {
|
|
|
148
148
|
strings: UIStrings,
|
|
149
149
|
title: i18nString(UIStrings.title),
|
|
150
150
|
description: i18nString(UIStrings.description),
|
|
151
|
+
docs: 'https://developer.chrome.com/docs/performance/insights/document-latency',
|
|
151
152
|
category: InsightCategory.ALL,
|
|
152
153
|
state: hasFailure ? 'fail' : 'pass',
|
|
153
154
|
...partialModel,
|