@paulirish/trace_engine 0.0.16 → 0.0.18
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/README.md +17 -22
- package/core/platform/ArrayUtilities.js.map +1 -1
- package/core/platform/DOMUtilities.js.map +1 -1
- package/core/platform/MapUtilities.d.ts +1 -0
- package/core/platform/MapUtilities.js +3 -0
- package/core/platform/MapUtilities.js.map +1 -1
- package/core/platform/MimeType.js +1 -0
- package/core/platform/MimeType.js.map +1 -1
- package/core/platform/NumberUtilities.js.map +1 -1
- package/core/platform/SetUtilities.js.map +1 -1
- package/core/platform/StringUtilities.js.map +1 -1
- package/core/platform/TypescriptUtilities.js.map +1 -1
- package/core/platform/UserVisibleError.js.map +1 -1
- package/generated/protocol.d.ts +100 -34
- package/models/cpu_profile/CPUProfileDataModel.js.map +1 -1
- package/models/cpu_profile/ProfileTreeModel.js.map +1 -1
- package/models/trace/EntriesFilter.d.ts +6 -1
- package/models/trace/EntriesFilter.js +11 -2
- package/models/trace/EntriesFilter.js.map +1 -1
- package/models/trace/LegacyTracingModel.js.map +1 -1
- package/models/trace/ModelImpl.js.map +1 -1
- package/models/trace/Processor.js +38 -32
- package/models/trace/Processor.js.map +1 -1
- package/models/trace/TracingManager.js.map +1 -1
- package/models/trace/extras/FetchNodes.d.ts +1 -1
- package/models/trace/extras/FetchNodes.js +1 -2
- package/models/trace/extras/FetchNodes.js.map +1 -1
- package/models/trace/extras/FilmStrip.js.map +1 -1
- package/models/trace/extras/MainThreadActivity.js.map +1 -1
- package/models/trace/extras/Metadata.d.ts +2 -2
- package/models/trace/extras/Metadata.js +10 -2
- package/models/trace/extras/Metadata.js.map +1 -1
- package/models/trace/handlers/AnimationHandler.js +1 -1
- package/models/trace/handlers/AnimationHandler.js.map +1 -1
- package/models/trace/handlers/AuctionWorkletsHandler.js.map +1 -1
- package/models/trace/handlers/FramesHandler.js.map +1 -1
- package/models/trace/handlers/GPUHandler.js +1 -1
- package/models/trace/handlers/GPUHandler.js.map +1 -1
- package/models/trace/handlers/InitiatorsHandler.js +32 -3
- package/models/trace/handlers/InitiatorsHandler.js.map +1 -1
- package/models/trace/handlers/InvalidationsHandler.js +1 -1
- package/models/trace/handlers/InvalidationsHandler.js.map +1 -1
- package/models/trace/handlers/LargestImagePaintHandler.js +1 -1
- package/models/trace/handlers/LargestImagePaintHandler.js.map +1 -1
- package/models/trace/handlers/LargestTextPaintHandler.js +1 -1
- package/models/trace/handlers/LargestTextPaintHandler.js.map +1 -1
- package/models/trace/handlers/LayerTreeHandler.js +3 -3
- package/models/trace/handlers/LayerTreeHandler.js.map +1 -1
- package/models/trace/handlers/LayoutShiftsHandler.d.ts +5 -5
- package/models/trace/handlers/LayoutShiftsHandler.js +6 -5
- package/models/trace/handlers/LayoutShiftsHandler.js.map +1 -1
- package/models/trace/handlers/MemoryHandler.js +1 -1
- package/models/trace/handlers/MemoryHandler.js.map +1 -1
- package/models/trace/handlers/MetaHandler.js +8 -8
- package/models/trace/handlers/MetaHandler.js.map +1 -1
- package/models/trace/handlers/NetworkRequestsHandler.js +2 -2
- package/models/trace/handlers/NetworkRequestsHandler.js.map +1 -1
- package/models/trace/handlers/PageLoadMetricsHandler.d.ts +11 -0
- package/models/trace/handlers/PageLoadMetricsHandler.js +9 -14
- package/models/trace/handlers/PageLoadMetricsHandler.js.map +1 -1
- package/models/trace/handlers/RendererHandler.js.map +1 -1
- package/models/trace/handlers/SamplesHandler.js +2 -2
- package/models/trace/handlers/SamplesHandler.js.map +1 -1
- package/models/trace/handlers/ScreenshotsHandler.js +2 -1
- package/models/trace/handlers/ScreenshotsHandler.js.map +1 -1
- package/models/trace/handlers/Threads.js.map +1 -1
- package/models/trace/handlers/UserInteractionsHandler.d.ts +2 -0
- package/models/trace/handlers/UserInteractionsHandler.js +21 -11
- package/models/trace/handlers/UserInteractionsHandler.js.map +1 -1
- package/models/trace/handlers/UserTimingsHandler.js +1 -0
- package/models/trace/handlers/UserTimingsHandler.js.map +1 -1
- package/models/trace/handlers/WarningsHandler.js +2 -2
- package/models/trace/handlers/WarningsHandler.js.map +1 -1
- package/models/trace/handlers/WorkersHandler.js +3 -3
- package/models/trace/handlers/WorkersHandler.js.map +1 -1
- package/models/trace/handlers/types.js.map +1 -1
- package/models/trace/helpers/SamplesIntegrator.js.map +1 -1
- package/models/trace/helpers/Timing.js.map +1 -1
- package/models/trace/helpers/Trace.js.map +1 -1
- package/models/trace/helpers/TreeHelpers.js.map +1 -1
- package/models/trace/insights/InsightRunners.d.ts +2 -0
- package/models/trace/insights/InsightRunners.js +2 -0
- package/models/trace/insights/InsightRunners.js.map +1 -1
- package/models/trace/insights/InteractionToNextPaint.d.ts +9 -0
- package/models/trace/insights/InteractionToNextPaint.js +35 -0
- package/models/trace/insights/InteractionToNextPaint.js.map +1 -0
- package/models/trace/insights/LargestContentfulPaint.d.ts +31 -0
- package/models/trace/insights/LargestContentfulPaint.js +104 -0
- package/models/trace/insights/LargestContentfulPaint.js.map +1 -0
- package/models/trace/insights/RenderBlocking.js.map +1 -1
- package/models/trace/insights/insights-tsconfig.json +2 -0
- package/models/trace/insights/types.d.ts +3 -1
- package/models/trace/insights/types.js +3 -0
- package/models/trace/insights/types.js.map +1 -1
- package/models/trace/root-causes/LayoutShift.d.ts +2 -2
- package/models/trace/root-causes/LayoutShift.js +19 -14
- package/models/trace/root-causes/LayoutShift.js.map +1 -1
- package/models/trace/root-causes/RootCauses.d.ts +1 -1
- package/models/trace/root-causes/RootCauses.js.map +1 -1
- package/models/trace/types/Configuration.js +10 -2
- package/models/trace/types/Configuration.js.map +1 -1
- package/models/trace/types/File.d.ts +6 -0
- package/models/trace/types/File.js.map +1 -1
- package/models/trace/types/TraceEvents.d.ts +23 -1
- package/models/trace/types/TraceEvents.js +6 -0
- package/models/trace/types/TraceEvents.js.map +1 -1
- package/package.json +1 -1
- package/PAUL.readme.md +0 -5
- package/core/platform/array-utilities.d.ts +0 -66
- package/core/platform/array-utilities.js +0 -199
- package/core/platform/array-utilities.js.map +0 -1
- package/core/platform/date-utilities.d.ts +0 -2
- package/core/platform/date-utilities.js +0 -14
- package/core/platform/date-utilities.js.map +0 -1
- package/core/platform/dcheck-tsconfig.json +0 -8
- package/core/platform/dcheck.d.ts +0 -4
- package/core/platform/dcheck.js +0 -5
- package/core/platform/dom-utilities.d.ts +0 -8
- package/core/platform/dom-utilities.js +0 -109
- package/core/platform/dom-utilities.js.map +0 -1
- package/core/platform/keyboard-utilities.d.ts +0 -17
- package/core/platform/keyboard-utilities.js +0 -22
- package/core/platform/keyboard-utilities.js.map +0 -1
- package/core/platform/map-utilities.d.ts +0 -18
- package/core/platform/map-utilities.js +0 -76
- package/core/platform/map-utilities.js.map +0 -1
- package/core/platform/number-utilities.d.ts +0 -15
- package/core/platform/number-utilities.js +0 -82
- package/core/platform/number-utilities.js.map +0 -1
- package/core/platform/promise-utilities.d.ts +0 -10
- package/core/platform/promise-utilities.js +0 -18
- package/core/platform/promise-utilities.js.map +0 -1
- package/core/platform/set-utilities.d.ts +0 -2
- package/core/platform/set-utilities.js +0 -23
- package/core/platform/set-utilities.js.map +0 -1
- package/core/platform/string-utilities.d.ts +0 -71
- package/core/platform/string-utilities.js +0 -513
- package/core/platform/string-utilities.js.map +0 -1
- package/core/platform/typescript-utilities.d.ts +0 -56
- package/core/platform/typescript-utilities.js +0 -25
- package/core/platform/typescript-utilities.js.map +0 -1
- /package/core/platform/{brand.d.ts → Brand.d.ts} +0 -0
- /package/core/platform/{brand.js → Brand.js} +0 -0
- /package/core/platform/{brand.js.map → Brand.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InteractionToNextPaint.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/InteractionToNextPaint.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAM7B,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAC9B,CAAC;AAOD,MAAM,UAAU,eAAe,CAAC,eAA0C,EAAE,OAAiC;IAC3G,MAAM,iBAAiB,GAAG,eAAe,CAAC,gBAAgB,CAAC,iBAAiB,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;QAC1F,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,KAAK,OAAO,CAAC,YAAY,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC;QAC9B,qDAAqD;QACrD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,sBAAsB,GAAG,IAAI,GAAG,EAAoC,CAAC;IAC3E,KAAK,MAAM,KAAK,IAAI,iBAAiB,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,KAAK,CAAC,aAAa,CAAC;QAChC,MAAM,OAAO,GAAG,sBAAsB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChD,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;YACxC,sBAAsB,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IACD,MAAM,2BAA2B,GAAG,CAAC,GAAG,sBAAsB,CAAC,MAAM,EAAE,CAAC,CAAC;IACzE,2BAA2B,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IAE1D,6EAA6E;IAC7E,+EAA+E;IAC/E,6EAA6E;IAC7E,iMAAiM;IACjM,MAAM,mBAAmB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,2BAA2B,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC;IAE7F,OAAO;QACL,uBAAuB,EAAE,2BAA2B,CAAC,CAAC,CAAC;QACvD,8BAA8B,EAAE,2BAA2B,CAAC,mBAAmB,CAAC;KACjF,CAAC;AACJ,CAAC","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\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 SyntheticInteractionPair} from '../types/TraceEvents.js';\n\nimport {type InsightResult, type NavigationInsightContext, type RequiredData} from './types.js';\n\nexport function deps(): ['UserInteractions'] {\n return ['UserInteractions'];\n}\n\ntype Result = InsightResult<{\n longestInteractionEvent?: SyntheticInteractionPair,\n highPercentileInteractionEvent?: SyntheticInteractionPair,\n}>;\n\nexport function generateInsight(traceParsedData: RequiredData<typeof deps>, context: NavigationInsightContext): Result {\n const interactionEvents = traceParsedData.UserInteractions.interactionEvents.filter(event => {\n return event.args.data.navigationId === context.navigationId;\n });\n\n if (!interactionEvents.length) {\n // A valid result, when there is no user interaction.\n return {};\n }\n\n const longestByInteractionId = new Map<number, SyntheticInteractionPair>();\n for (const event of interactionEvents) {\n const key = event.interactionId;\n const longest = longestByInteractionId.get(key);\n if (!longest || event.dur > longest.dur) {\n longestByInteractionId.set(key, event);\n }\n }\n const normalizedInteractionEvents = [...longestByInteractionId.values()];\n normalizedInteractionEvents.sort((a, b) => b.dur - a.dur);\n\n // INP is the \"nearest-rank\"/inverted_cdf 98th percentile, except Chrome only\n // keeps the 10 worst events around, so it can never be more than the 10th from\n // last array element. To keep things simpler, sort desc and pick from front.\n // See https://source.chromium.org/chromium/chromium/src/+/main:components/page_load_metrics/browser/responsiveness_metrics_normalization.cc;l=45-59;drc=cb0f9c8b559d9c7c3cb4ca94fc1118cc015d38ad\n const highPercentileIndex = Math.min(9, Math.floor(normalizedInteractionEvents.length / 50));\n\n return {\n longestInteractionEvent: normalizedInteractionEvents[0],\n highPercentileInteractionEvent: normalizedInteractionEvents[highPercentileIndex],\n };\n}\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as Types from '../types/types.js';
|
|
2
|
+
import { type InsightResult, type NavigationInsightContext, type RequiredData } from './types.js';
|
|
3
|
+
export declare function deps(): ['NetworkRequests', 'PageLoadMetrics', 'LargestImagePaint', 'Meta'];
|
|
4
|
+
export interface LCPPhases {
|
|
5
|
+
/**
|
|
6
|
+
* The time between when the user initiates loading the page until when
|
|
7
|
+
* the browser receives the first byte of the html response.
|
|
8
|
+
*/
|
|
9
|
+
ttfb: Types.Timing.MilliSeconds;
|
|
10
|
+
/**
|
|
11
|
+
* The time between ttfb and the LCP resource request being started.
|
|
12
|
+
* For a text LCP, this is undefined given no resource is loaded.
|
|
13
|
+
*/
|
|
14
|
+
loadDelay?: Types.Timing.MilliSeconds;
|
|
15
|
+
/**
|
|
16
|
+
* The time it takes to load the LCP resource.
|
|
17
|
+
*/
|
|
18
|
+
loadTime?: Types.Timing.MilliSeconds;
|
|
19
|
+
/**
|
|
20
|
+
* The time between when the LCP resource finishes loading and when
|
|
21
|
+
* the LCP element is rendered.
|
|
22
|
+
*/
|
|
23
|
+
renderDelay: Types.Timing.MilliSeconds;
|
|
24
|
+
}
|
|
25
|
+
export declare function generateInsight(traceParsedData: RequiredData<typeof deps>, context: NavigationInsightContext): InsightResult<{
|
|
26
|
+
lcpMs?: Types.Timing.MilliSeconds;
|
|
27
|
+
phases?: LCPPhases;
|
|
28
|
+
shouldRemoveLazyLoading?: boolean;
|
|
29
|
+
shouldIncreasePriorityHint?: boolean;
|
|
30
|
+
shouldPreloadImage?: boolean;
|
|
31
|
+
}>;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// Copyright 2024 The Chromium Authors. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
import * as Handlers from '../handlers/handlers.js';
|
|
5
|
+
import * as Helpers from '../helpers/helpers.js';
|
|
6
|
+
import * as Types from '../types/types.js';
|
|
7
|
+
import { InsightWarning } from './types.js';
|
|
8
|
+
export function deps() {
|
|
9
|
+
return ['NetworkRequests', 'PageLoadMetrics', 'LargestImagePaint', 'Meta'];
|
|
10
|
+
}
|
|
11
|
+
function breakdownPhases(nav, mainRequest, lcpMs, lcpRequest) {
|
|
12
|
+
const mainReqTiming = mainRequest.args.data.timing;
|
|
13
|
+
if (!mainReqTiming) {
|
|
14
|
+
throw new Error('no timing for main resource');
|
|
15
|
+
}
|
|
16
|
+
const firstDocByteTs = Helpers.Timing.secondsToMicroseconds(mainReqTiming.requestTime) +
|
|
17
|
+
Helpers.Timing.millisecondsToMicroseconds(mainReqTiming.receiveHeadersStart);
|
|
18
|
+
const firstDocByteTiming = Types.Timing.MicroSeconds(firstDocByteTs - nav.ts);
|
|
19
|
+
const ttfb = Helpers.Timing.microSecondsToMilliseconds(firstDocByteTiming);
|
|
20
|
+
let renderDelay = Types.Timing.MilliSeconds(lcpMs - ttfb);
|
|
21
|
+
if (!lcpRequest) {
|
|
22
|
+
return { ttfb, renderDelay };
|
|
23
|
+
}
|
|
24
|
+
const lcpStartTs = Types.Timing.MicroSeconds(lcpRequest.ts - nav.ts);
|
|
25
|
+
const resourceStart = Helpers.Timing.microSecondsToMilliseconds(lcpStartTs);
|
|
26
|
+
const lcpReqEndTs = Types.Timing.MicroSeconds(lcpRequest.args.data.syntheticData.finishTime - nav.ts);
|
|
27
|
+
const resourceEnd = Helpers.Timing.microSecondsToMilliseconds(lcpReqEndTs);
|
|
28
|
+
const loadDelay = Types.Timing.MilliSeconds(resourceStart - ttfb);
|
|
29
|
+
const loadTime = Types.Timing.MilliSeconds(resourceEnd - resourceStart);
|
|
30
|
+
renderDelay = Types.Timing.MilliSeconds(lcpMs - resourceEnd);
|
|
31
|
+
return {
|
|
32
|
+
ttfb,
|
|
33
|
+
loadDelay,
|
|
34
|
+
loadTime,
|
|
35
|
+
renderDelay,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function findLCPRequest(traceParsedData, context, lcpEvent) {
|
|
39
|
+
const lcpNodeId = lcpEvent.args.data?.nodeId;
|
|
40
|
+
if (!lcpNodeId) {
|
|
41
|
+
throw new Error('no lcp node id');
|
|
42
|
+
}
|
|
43
|
+
const imagePaint = traceParsedData.LargestImagePaint.get(lcpNodeId);
|
|
44
|
+
if (!imagePaint) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const lcpUrl = imagePaint.args.data?.imageUrl;
|
|
48
|
+
if (!lcpUrl) {
|
|
49
|
+
throw new Error('no lcp url');
|
|
50
|
+
}
|
|
51
|
+
// Look for the LCP resource.
|
|
52
|
+
const lcpResource = traceParsedData.NetworkRequests.byTime.find(req => {
|
|
53
|
+
const nav = Helpers.Trace.getNavigationForTraceEvent(req, context.frameId, traceParsedData.Meta.navigationsByFrameId);
|
|
54
|
+
return (nav?.args.data?.navigationId === context.navigationId) && (req.args.data.url === lcpUrl);
|
|
55
|
+
});
|
|
56
|
+
if (!lcpResource) {
|
|
57
|
+
throw new Error('no lcp resource found');
|
|
58
|
+
}
|
|
59
|
+
return lcpResource;
|
|
60
|
+
}
|
|
61
|
+
export function generateInsight(traceParsedData, context) {
|
|
62
|
+
const networkRequests = traceParsedData.NetworkRequests;
|
|
63
|
+
const nav = traceParsedData.Meta.navigationsByNavigationId.get(context.navigationId);
|
|
64
|
+
if (!nav) {
|
|
65
|
+
throw new Error('no trace navigation');
|
|
66
|
+
}
|
|
67
|
+
const frameMetrics = traceParsedData.PageLoadMetrics.metricScoresByFrameId.get(context.frameId);
|
|
68
|
+
if (!frameMetrics) {
|
|
69
|
+
throw new Error('no frame metrics');
|
|
70
|
+
}
|
|
71
|
+
const navMetrics = frameMetrics.get(context.navigationId);
|
|
72
|
+
if (!navMetrics) {
|
|
73
|
+
throw new Error('no navigation metrics');
|
|
74
|
+
}
|
|
75
|
+
const metricScore = navMetrics.get("LCP" /* Handlers.ModelHandlers.PageLoadMetrics.MetricName.LCP */);
|
|
76
|
+
const lcpEvent = metricScore?.event;
|
|
77
|
+
if (!lcpEvent || !Types.TraceEvents.isTraceEventLargestContentfulPaintCandidate(lcpEvent)) {
|
|
78
|
+
return { warnings: [InsightWarning.NO_LCP] };
|
|
79
|
+
}
|
|
80
|
+
const lcpTiming = metricScore.timing;
|
|
81
|
+
const lcpMs = Helpers.Timing.microSecondsToMilliseconds(lcpTiming);
|
|
82
|
+
const lcpResource = findLCPRequest(traceParsedData, context, lcpEvent);
|
|
83
|
+
const mainReq = networkRequests.byTime.find(req => req.args.data.requestId === context.navigationId);
|
|
84
|
+
if (!mainReq) {
|
|
85
|
+
return { lcpMs, warnings: [InsightWarning.NO_DOCUMENT_REQUEST] };
|
|
86
|
+
}
|
|
87
|
+
if (!lcpResource) {
|
|
88
|
+
return {
|
|
89
|
+
lcpMs,
|
|
90
|
+
phases: breakdownPhases(nav, mainReq, lcpMs, lcpResource),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const imageLoadingAttr = lcpEvent.args.data?.loadingAttr;
|
|
94
|
+
const imagePreloaded = lcpResource?.args.data.isLinkPreload || lcpResource?.args.data.initiator?.type === 'preload';
|
|
95
|
+
const imageFetchPriorityHint = lcpResource?.args.data.fetchPriorityHint;
|
|
96
|
+
return {
|
|
97
|
+
lcpMs,
|
|
98
|
+
phases: breakdownPhases(nav, mainReq, lcpMs, lcpResource),
|
|
99
|
+
shouldRemoveLazyLoading: imageLoadingAttr === 'lazy',
|
|
100
|
+
shouldIncreasePriorityHint: imageFetchPriorityHint !== 'high',
|
|
101
|
+
shouldPreloadImage: !imagePreloaded,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=LargestContentfulPaint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LargestContentfulPaint.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/LargestContentfulPaint.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\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 Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {type InsightResult, InsightWarning, type NavigationInsightContext, type RequiredData} from './types.js';\n\nexport function deps(): ['NetworkRequests', 'PageLoadMetrics', 'LargestImagePaint', 'Meta'] {\n return ['NetworkRequests', 'PageLoadMetrics', 'LargestImagePaint', 'Meta'];\n}\n\nexport interface LCPPhases {\n /**\n * The time between when the user initiates loading the page until when\n * the browser receives the first byte of the html response.\n */\n ttfb: Types.Timing.MilliSeconds;\n /**\n * The time between ttfb and the LCP resource request being started.\n * For a text LCP, this is undefined given no resource is loaded.\n */\n loadDelay?: Types.Timing.MilliSeconds;\n /**\n * The time it takes to load the LCP resource.\n */\n loadTime?: Types.Timing.MilliSeconds;\n /**\n * The time between when the LCP resource finishes loading and when\n * the LCP element is rendered.\n */\n renderDelay: Types.Timing.MilliSeconds;\n}\n\nfunction breakdownPhases(\n nav: Types.TraceEvents.TraceEventNavigationStart, mainRequest: Types.TraceEvents.SyntheticNetworkRequest,\n lcpMs: Types.Timing.MilliSeconds, lcpRequest: Types.TraceEvents.SyntheticNetworkRequest|null): LCPPhases {\n const mainReqTiming = mainRequest.args.data.timing;\n if (!mainReqTiming) {\n throw new Error('no timing for main resource');\n }\n const firstDocByteTs = Helpers.Timing.secondsToMicroseconds(mainReqTiming.requestTime) +\n Helpers.Timing.millisecondsToMicroseconds(mainReqTiming.receiveHeadersStart);\n\n const firstDocByteTiming = Types.Timing.MicroSeconds(firstDocByteTs - nav.ts);\n const ttfb = Helpers.Timing.microSecondsToMilliseconds(firstDocByteTiming);\n let renderDelay = Types.Timing.MilliSeconds(lcpMs - ttfb);\n\n if (!lcpRequest) {\n return {ttfb, renderDelay};\n }\n\n const lcpStartTs = Types.Timing.MicroSeconds(lcpRequest.ts - nav.ts);\n const resourceStart = Helpers.Timing.microSecondsToMilliseconds(lcpStartTs);\n\n const lcpReqEndTs = Types.Timing.MicroSeconds(lcpRequest.args.data.syntheticData.finishTime - nav.ts);\n const resourceEnd = Helpers.Timing.microSecondsToMilliseconds(lcpReqEndTs);\n\n const loadDelay = Types.Timing.MilliSeconds(resourceStart - ttfb);\n const loadTime = Types.Timing.MilliSeconds(resourceEnd - resourceStart);\n renderDelay = Types.Timing.MilliSeconds(lcpMs - resourceEnd);\n\n return {\n ttfb,\n loadDelay,\n loadTime,\n renderDelay,\n };\n}\n\nfunction findLCPRequest(\n traceParsedData: RequiredData<typeof deps>, context: NavigationInsightContext,\n lcpEvent: Types.TraceEvents.TraceEventLargestContentfulPaintCandidate): Types.TraceEvents.SyntheticNetworkRequest|\n null {\n const lcpNodeId = lcpEvent.args.data?.nodeId;\n if (!lcpNodeId) {\n throw new Error('no lcp node id');\n }\n\n const imagePaint = traceParsedData.LargestImagePaint.get(lcpNodeId);\n if (!imagePaint) {\n return null;\n }\n\n const lcpUrl = imagePaint.args.data?.imageUrl;\n if (!lcpUrl) {\n throw new Error('no lcp url');\n }\n // Look for the LCP resource.\n const lcpResource = traceParsedData.NetworkRequests.byTime.find(req => {\n const nav =\n Helpers.Trace.getNavigationForTraceEvent(req, context.frameId, traceParsedData.Meta.navigationsByFrameId);\n return (nav?.args.data?.navigationId === context.navigationId) && (req.args.data.url === lcpUrl);\n });\n\n if (!lcpResource) {\n throw new Error('no lcp resource found');\n }\n\n return lcpResource;\n}\n\nexport function generateInsight(\n traceParsedData: RequiredData<typeof deps>, context: NavigationInsightContext): InsightResult<{\n lcpMs?: Types.Timing.MilliSeconds,\n phases?: LCPPhases,\n shouldRemoveLazyLoading?: boolean,\n shouldIncreasePriorityHint?: boolean,\n shouldPreloadImage?: boolean,\n}> {\n const networkRequests = traceParsedData.NetworkRequests;\n\n const nav = traceParsedData.Meta.navigationsByNavigationId.get(context.navigationId);\n if (!nav) {\n throw new Error('no trace navigation');\n }\n\n const frameMetrics = traceParsedData.PageLoadMetrics.metricScoresByFrameId.get(context.frameId);\n if (!frameMetrics) {\n throw new Error('no frame metrics');\n }\n\n const navMetrics = frameMetrics.get(context.navigationId);\n if (!navMetrics) {\n throw new Error('no navigation metrics');\n }\n const metricScore = navMetrics.get(Handlers.ModelHandlers.PageLoadMetrics.MetricName.LCP);\n const lcpEvent = metricScore?.event;\n if (!lcpEvent || !Types.TraceEvents.isTraceEventLargestContentfulPaintCandidate(lcpEvent)) {\n return {warnings: [InsightWarning.NO_LCP]};\n }\n\n const lcpTiming = metricScore.timing;\n const lcpMs = Helpers.Timing.microSecondsToMilliseconds(lcpTiming);\n const lcpResource = findLCPRequest(traceParsedData, context, lcpEvent);\n const mainReq = networkRequests.byTime.find(req => req.args.data.requestId === context.navigationId);\n if (!mainReq) {\n return {lcpMs, warnings: [InsightWarning.NO_DOCUMENT_REQUEST]};\n }\n\n if (!lcpResource) {\n return {\n lcpMs,\n phases: breakdownPhases(nav, mainReq, lcpMs, lcpResource),\n };\n }\n\n const imageLoadingAttr = lcpEvent.args.data?.loadingAttr;\n const imagePreloaded = lcpResource?.args.data.isLinkPreload || lcpResource?.args.data.initiator?.type === 'preload';\n const imageFetchPriorityHint = lcpResource?.args.data.fetchPriorityHint;\n\n return {\n lcpMs,\n phases: breakdownPhases(nav, mainReq, lcpMs, lcpResource),\n shouldRemoveLazyLoading: imageLoadingAttr === 'lazy',\n shouldIncreasePriorityHint: imageFetchPriorityHint !== 'high',\n shouldPreloadImage: !imagePreloaded,\n };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RenderBlocking.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/RenderBlocking.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,QAAQ,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AAGjD,OAAO,EAAqB,cAAc,EAAmD,MAAM,YAAY,CAAC;AAEhH,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,eAA0C,EAAE,OAAiC;IAE3G,MAAM,YAAY,GAAG,eAAe,CAAC,eAAe,CAAC,qBAAqB,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;QACtE,EAAE,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC;QAC3B,EAAE,GAAG,iEAAsD;QAC3D,EAAE,KAAK,EAAE,EAAE,CAAC;IACrC,IAAI,CAAC,YAAY,EAAE;
|
|
1
|
+
{"version":3,"file":"RenderBlocking.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/RenderBlocking.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAE7B,OAAO,KAAK,QAAQ,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,OAAO,MAAM,uBAAuB,CAAC;AAGjD,OAAO,EAAqB,cAAc,EAAmD,MAAM,YAAY,CAAC;AAEhH,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,eAA0C,EAAE,OAAiC;IAE3G,MAAM,YAAY,GAAG,eAAe,CAAC,eAAe,CAAC,qBAAqB,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC;QACtE,EAAE,GAAG,CAAC,OAAO,CAAC,YAAY,CAAC;QAC3B,EAAE,GAAG,iEAAsD;QAC3D,EAAE,KAAK,EAAE,EAAE,CAAC;IACrC,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO;YACL,sBAAsB,EAAE,EAAE;YAC1B,QAAQ,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC;SACjC,CAAC;IACJ,CAAC;IAED,MAAM,sBAAsB,GAAG,EAAE,CAAC;IAClC,KAAK,MAAM,GAAG,IAAI,eAAe,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC;QACzD,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YAC5C,SAAS;QACX,CAAC;QAED,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,KAAK,UAAU,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,KAAK,yBAAyB,EAAE,CAAC;YAC9G,SAAS;QACX,CAAC;QAED,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,UAAU,GAAG,YAAY,EAAE,CAAC;YAC1D,SAAS;QACX,CAAC;QAED,MAAM,UAAU,GACZ,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,eAAe,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAC9G,IAAI,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,CAAC,YAAY,EAAE,CAAC;YACjE,SAAS;QACX,CAAC;QAED,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;IAED,OAAO;QACL,sBAAsB;KACvB,CAAC;AACJ,CAAC","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\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 Handlers from '../handlers/handlers.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport type * as Types from '../types/types.js';\n\nimport {type InsightResult, InsightWarning, type NavigationInsightContext, type RequiredData} from './types.js';\n\nexport function deps(): ['NetworkRequests', 'PageLoadMetrics'] {\n return ['NetworkRequests', 'PageLoadMetrics'];\n}\n\nexport function generateInsight(traceParsedData: RequiredData<typeof deps>, context: NavigationInsightContext):\n InsightResult<{renderBlockingRequests: Types.TraceEvents.SyntheticNetworkRequest[]}> {\n const firstPaintTs = traceParsedData.PageLoadMetrics.metricScoresByFrameId.get(context.frameId)\n ?.get(context.navigationId)\n ?.get(Handlers.ModelHandlers.PageLoadMetrics.MetricName.FP)\n ?.event?.ts;\n if (!firstPaintTs) {\n return {\n renderBlockingRequests: [],\n warnings: [InsightWarning.NO_FP],\n };\n }\n\n const renderBlockingRequests = [];\n for (const req of traceParsedData.NetworkRequests.byTime) {\n if (req.args.data.frame !== context.frameId) {\n continue;\n }\n\n if (req.args.data.renderBlocking !== 'blocking' && req.args.data.renderBlocking !== 'in_body_parser_blocking') {\n continue;\n }\n\n if (req.args.data.syntheticData.finishTime > firstPaintTs) {\n continue;\n }\n\n const navigation =\n Helpers.Trace.getNavigationForTraceEvent(req, context.frameId, traceParsedData.Meta.navigationsByFrameId);\n if (navigation?.args.data?.navigationId !== context.navigationId) {\n continue;\n }\n\n renderBlockingRequests.push(req);\n }\n\n return {\n renderBlockingRequests,\n };\n}\n"]}
|
|
@@ -30,6 +30,8 @@
|
|
|
30
30
|
},
|
|
31
31
|
"files": [
|
|
32
32
|
"../../../../../../../front_end/models/trace/insights/InsightRunners.ts",
|
|
33
|
+
"../../../../../../../front_end/models/trace/insights/InteractionToNextPaint.ts",
|
|
34
|
+
"../../../../../../../front_end/models/trace/insights/LargestContentfulPaint.ts",
|
|
33
35
|
"../../../../../../../front_end/models/trace/insights/RenderBlocking.ts",
|
|
34
36
|
"../../../../../../../front_end/models/trace/insights/types.ts",
|
|
35
37
|
"../../../../../../../front_end/legacy/legacy-defs.d.ts",
|
|
@@ -9,7 +9,9 @@ export interface NavigationInsightContext {
|
|
|
9
9
|
}
|
|
10
10
|
type InsightRunnersType = typeof InsightsRunners;
|
|
11
11
|
export declare enum InsightWarning {
|
|
12
|
-
NO_FP = "NO_FP"
|
|
12
|
+
NO_FP = "NO_FP",
|
|
13
|
+
NO_LCP = "NO_LCP",
|
|
14
|
+
NO_DOCUMENT_REQUEST = "NO_DOCUMENT_REQUEST"
|
|
13
15
|
}
|
|
14
16
|
export type InsightResult<R extends Record<string, unknown>> = R & {
|
|
15
17
|
warnings?: InsightWarning[];
|
|
@@ -4,5 +4,8 @@
|
|
|
4
4
|
export var InsightWarning;
|
|
5
5
|
(function (InsightWarning) {
|
|
6
6
|
InsightWarning["NO_FP"] = "NO_FP";
|
|
7
|
+
InsightWarning["NO_LCP"] = "NO_LCP";
|
|
8
|
+
// No network request could be identified as the primary HTML document.
|
|
9
|
+
InsightWarning["NO_DOCUMENT_REQUEST"] = "NO_DOCUMENT_REQUEST";
|
|
7
10
|
})(InsightWarning || (InsightWarning = {}));
|
|
8
11
|
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/types.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAgB7B,MAAM,CAAN,IAAY,
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/insights/types.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAgB7B,MAAM,CAAN,IAAY,cAKX;AALD,WAAY,cAAc;IACxB,iCAAe,CAAA;IACf,mCAAiB,CAAA;IACjB,uEAAuE;IACvE,6DAA2C,CAAA;AAC7C,CAAC,EALW,cAAc,KAAd,cAAc,QAKzB","sourcesContent":["// Copyright 2024 The Chromium Authors. All rights reserved.\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 Handlers from '../handlers/handlers.js';\n\nimport type * as InsightsRunners from './InsightRunners.js';\n\n/**\n * Context for which navigation an insight should look at.\n */\nexport interface NavigationInsightContext {\n frameId: string;\n navigationId: string;\n}\n\ntype InsightRunnersType = typeof InsightsRunners;\n\nexport enum InsightWarning {\n NO_FP = 'NO_FP',\n NO_LCP = 'NO_LCP',\n // No network request could be identified as the primary HTML document.\n NO_DOCUMENT_REQUEST = 'NO_DOCUMENT_REQUEST',\n}\n\nexport type InsightResult<R extends Record<string, unknown>> = R&{\n warnings?: InsightWarning[],\n};\n\n/**\n * Contains insights for a specific navigation.\n */\nexport type NavigationInsightData<H extends {[key: string]: Handlers.Types.TraceEventHandler}> = {\n [I in keyof EnabledInsightRunners<H>]: ReturnType<EnabledInsightRunners<H>[I]>|Error;\n};\n\n/**\n * Contains insights for the entire trace. Insights are grouped by `navigationId`.\n */\nexport type TraceInsightData<H extends {[key: string]: Handlers.Types.TraceEventHandler}> =\n Map<string, NavigationInsightData<H>>;\n\n/**\n * Maps each enabled insight name to its generate function. Insights that are disabled (i.e. missing one or more dependencies) will be unset.\n */\nexport type EnabledInsightRunners<H extends {[key: string]: Handlers.Types.TraceEventHandler}> = {\n [I in keyof InsightRunnersType]:\n [Handlers.Types.EnabledHandlerDataWithMeta<H>] extends [Parameters<InsightRunnersType[I]['generateInsight']>[0]] ?\n (traceParsedData: Handlers.Types.EnabledHandlerDataWithMeta<H>, context: NavigationInsightContext) =>\n ReturnType<InsightRunnersType[I]['generateInsight']>:\n never;\n};\n\n/**\n * Represents the narrow set of dependencies defined by an insight's `deps()` function. `Meta` is always included regardless of `deps()`.\n */\nexport type RequiredData<D extends() => Array<keyof typeof Handlers.ModelHandlers>> =\n Handlers.Types.EnabledHandlerDataWithMeta<Pick<typeof Handlers.ModelHandlers, ReturnType<D>[number]>>;\n"]}
|
|
@@ -67,12 +67,12 @@ export declare class LayoutShiftRootCauses {
|
|
|
67
67
|
* Given a LayoutInvalidation trace event, determines if it was dispatched
|
|
68
68
|
* because a media element without dimensions was resized.
|
|
69
69
|
*/
|
|
70
|
-
getUnsizedMediaRootCause(
|
|
70
|
+
getUnsizedMediaRootCause(layoutInvalidation: Types.TraceEvents.TraceEventLayoutInvalidationTracking, layoutInvalidationNodeId: Protocol.DOM.NodeId): Promise<UnsizedMedia | null>;
|
|
71
71
|
/**
|
|
72
72
|
* Given a LayoutInvalidation trace event, determines if it was dispatched
|
|
73
73
|
* because a node, which is an ancestor to an iframe, was injected.
|
|
74
74
|
*/
|
|
75
|
-
getIframeRootCause(
|
|
75
|
+
getIframeRootCause(layoutInvalidation: Types.TraceEvents.TraceEventLayoutInvalidationTracking, layoutInvalidationNodeId: Protocol.DOM.NodeId): Promise<InjectedIframe | null>;
|
|
76
76
|
/**
|
|
77
77
|
* Given a layout invalidation event and a sorted array, returns the subset of requests that arrived within a
|
|
78
78
|
* 500ms window before the layout invalidation.
|
|
@@ -113,15 +113,12 @@ export class LayoutShiftRootCauses {
|
|
|
113
113
|
const fontChangeRootCause = this.getFontChangeRootCause(layoutInvalidation, nextPrePaint, modelData);
|
|
114
114
|
const renderBlockRootCause = this.getRenderBlockRootCause(layoutInvalidation, nextPrePaint, modelData);
|
|
115
115
|
const layoutInvalidationNodeId = nodeIdsByBackendIdMap.get(layoutInvalidation.args.data.nodeId);
|
|
116
|
-
const layoutInvalidationNode = layoutInvalidationNodeId !== undefined ?
|
|
117
|
-
await this.#protocolInterface.getNode(layoutInvalidationNodeId) :
|
|
118
|
-
null;
|
|
119
116
|
let unsizedMediaRootCause = null;
|
|
120
117
|
let iframeRootCause = null;
|
|
121
|
-
if (
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
iframeRootCause = this.getIframeRootCause(layoutInvalidation
|
|
118
|
+
if (layoutInvalidationNodeId !== undefined &&
|
|
119
|
+
Types.TraceEvents.isTraceEventLayoutInvalidationTracking(layoutInvalidation)) {
|
|
120
|
+
unsizedMediaRootCause = await this.getUnsizedMediaRootCause(layoutInvalidation, layoutInvalidationNodeId);
|
|
121
|
+
iframeRootCause = await this.getIframeRootCause(layoutInvalidation, layoutInvalidationNodeId);
|
|
125
122
|
}
|
|
126
123
|
if (!unsizedMediaRootCause && !iframeRootCause && !fontChangeRootCause && !renderBlockRootCause) {
|
|
127
124
|
continue;
|
|
@@ -215,9 +212,13 @@ export class LayoutShiftRootCauses {
|
|
|
215
212
|
* Given a LayoutInvalidation trace event, determines if it was dispatched
|
|
216
213
|
* because a media element without dimensions was resized.
|
|
217
214
|
*/
|
|
218
|
-
async getUnsizedMediaRootCause(
|
|
215
|
+
async getUnsizedMediaRootCause(layoutInvalidation, layoutInvalidationNodeId) {
|
|
219
216
|
// Filter events to resizes only.
|
|
220
|
-
if (reason !== "Size changed" /* Types.TraceEvents.LayoutInvalidationReason.SIZE_CHANGED */) {
|
|
217
|
+
if (layoutInvalidation.args.data.reason !== "Size changed" /* Types.TraceEvents.LayoutInvalidationReason.SIZE_CHANGED */) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
const layoutInvalidationNode = await this.#protocolInterface.getNode(layoutInvalidationNodeId);
|
|
221
|
+
if (!layoutInvalidationNode) {
|
|
221
222
|
return null;
|
|
222
223
|
}
|
|
223
224
|
const computedStylesList = await this.#protocolInterface.getComputedStyleForNode(layoutInvalidationNode.nodeId);
|
|
@@ -236,13 +237,17 @@ export class LayoutShiftRootCauses {
|
|
|
236
237
|
* Given a LayoutInvalidation trace event, determines if it was dispatched
|
|
237
238
|
* because a node, which is an ancestor to an iframe, was injected.
|
|
238
239
|
*/
|
|
239
|
-
getIframeRootCause(
|
|
240
|
-
if (
|
|
241
|
-
reason !== "Style changed" /* Types.TraceEvents.LayoutInvalidationReason.STYLE_CHANGED */ &&
|
|
242
|
-
reason !== "Added to layout" /* Types.TraceEvents.LayoutInvalidationReason.ADDED_TO_LAYOUT */) {
|
|
240
|
+
async getIframeRootCause(layoutInvalidation, layoutInvalidationNodeId) {
|
|
241
|
+
if (layoutInvalidation.args.data.nodeName?.startsWith('IFRAME') &&
|
|
242
|
+
layoutInvalidation.args.data.reason !== "Style changed" /* Types.TraceEvents.LayoutInvalidationReason.STYLE_CHANGED */ &&
|
|
243
|
+
layoutInvalidation.args.data.reason !== "Added to layout" /* Types.TraceEvents.LayoutInvalidationReason.ADDED_TO_LAYOUT */) {
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
const layoutInvalidationNode = await this.#protocolInterface.getNode(layoutInvalidationNodeId);
|
|
247
|
+
if (!layoutInvalidationNode) {
|
|
243
248
|
return null;
|
|
244
249
|
}
|
|
245
|
-
const iframe = firstIframeInDOMTree(
|
|
250
|
+
const iframe = firstIframeInDOMTree(layoutInvalidationNode);
|
|
246
251
|
if (!iframe) {
|
|
247
252
|
return null;
|
|
248
253
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LayoutShift.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/root-causes/LayoutShift.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2023 The Chromium Authors. All rights reserved.\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 Platform from '../../../core/platform/platform.js';\nimport type * as Protocol from '../../../generated/protocol.js';\nimport {type TraceParseData} from '../handlers/types.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {type RootCauseProtocolInterface} from './RootCauses.js';\n\nexport type CSSDimensions = {\n width?: string,\n height?: string,\n aspectRatio?: string,\n};\n\nexport interface UnsizedMedia {\n node: Protocol.DOM.Node;\n authoredDimensions?: CSSDimensions;\n computedDimensions: CSSDimensions;\n}\n\nexport interface InjectedIframe {\n iframe: Protocol.DOM.Node;\n}\n\nexport interface RootCauseRequest {\n request: Types.TraceEvents.SyntheticNetworkRequest;\n initiator?: Protocol.Network.Initiator;\n}\n\nexport interface FontChange extends RootCauseRequest {\n fontFace: Protocol.CSS.FontFace;\n}\n\nexport interface RenderBlockingRequest extends RootCauseRequest {}\n\nexport interface LayoutShiftRootCausesData {\n unsizedMedia: UnsizedMedia[];\n iframes: InjectedIframe[];\n fontChanges: FontChange[];\n renderBlockingRequests: RenderBlockingRequest[];\n scriptStackTrace: Types.TraceEvents.TraceEventCallFrame[];\n}\n\nconst fontRequestsByPrePaint = new Map<Types.TraceEvents.TraceEventPrePaint, FontChange[]|null>();\nconst renderBlocksByPrePaint = new Map<Types.TraceEvents.TraceEventPrePaint, RenderBlockingRequest[]|null>();\n\nfunction setDefaultValue(\n map: Map<Types.TraceEvents.TraceEventLayoutShift, LayoutShiftRootCausesData>,\n shift: Types.TraceEvents.TraceEventLayoutShift): void {\n Platform.MapUtilities.getWithDefault(map, shift, () => {\n return {\n unsizedMedia: [],\n iframes: [],\n fontChanges: [],\n renderBlockingRequests: [],\n scriptStackTrace: [],\n };\n });\n}\n\n// Important: we purposefully treat `potentially_blocking` as\n// non-render-blocking here because:\n// 1. An async script can run on the main thread at any point, including before\n// the page is loaded\n// 2. An async script will never block the parsing and rendering process of the\n// browser.\n// 3. Therefore, from a developer's point of view, there is nothing more they\n// can do if they've put `async` on, and within the context of Insights, we\n// shouldn't report an async script as render blocking.\n// In the future we may want to consider suggesting the use of `defer` over\n// `async`, as it doesn't have this concern, but for now we'll allow `async`\n// and not report it as an issue.\nconst NON_RENDER_BLOCKING_VALUES = new Set<Types.TraceEvents.RenderBlocking>([\n 'non_blocking',\n 'potentially_blocking',\n]);\nfunction networkRequestIsRenderBlockingInFrame(\n event: Types.TraceEvents.SyntheticNetworkRequest, frameId: string): boolean {\n const isRenderBlocking = !NON_RENDER_BLOCKING_VALUES.has(event.args.data.renderBlocking);\n return isRenderBlocking && event.args.data.frame === frameId;\n}\n\nexport class LayoutShiftRootCauses {\n #protocolInterface: RootCauseProtocolInterface;\n #rootCauseCacheMap = new Map<Types.TraceEvents.TraceEventLayoutShift, LayoutShiftRootCausesData>();\n\n constructor(protocolInterface: RootCauseProtocolInterface) {\n this.#protocolInterface = protocolInterface;\n }\n\n /**\n * Calculates the potential root causes for a given layout shift event. Once\n * calculated, this data is cached.\n * Note: because you need all layout shift data at once to calculate these\n * correctly, this function will parse the root causes for _all_ layout shift\n * events the first time that it's called. That then populates the cache for\n * each shift, so any subsequent calls are just a constant lookup.\n */\n async rootCausesForEvent(modelData: TraceParseData, event: Types.TraceEvents.TraceEventLayoutShift):\n Promise<Readonly<LayoutShiftRootCausesData>|null> {\n const cachedResult = this.#rootCauseCacheMap.get(event);\n if (cachedResult) {\n return cachedResult;\n }\n\n const allLayoutShifts = modelData.LayoutShifts.clusters.flatMap(cluster => cluster.events);\n // Make sure a value in the cache is set even for shifts that don't have a root cause,\n // so that we don't have to recompute when no root causes are found. In case a cause\n // for a shift is found, the default value is replaced.\n allLayoutShifts.forEach(shift => setDefaultValue(this.#rootCauseCacheMap, shift));\n\n // Populate the cache\n await this.blameShifts(\n allLayoutShifts,\n modelData,\n );\n\n const resultForEvent = this.#rootCauseCacheMap.get(event);\n if (!resultForEvent) {\n // No root causes available for this layout shift.\n return null;\n }\n return resultForEvent;\n }\n\n /**\n * Determines potential root causes for shifts\n */\n async blameShifts(\n layoutShifts: Types.TraceEvents.TraceEventLayoutShift[],\n modelData: TraceParseData,\n ): Promise<void> {\n await this.linkShiftsToLayoutInvalidations(layoutShifts, modelData);\n this.linkShiftsToLayoutEvents(layoutShifts, modelData);\n }\n\n /**\n * \"LayoutInvalidations\" are a set of trace events dispatched in Blink under the name\n * \"layoutInvalidationTracking\", which track invalidations on the \"Layout\"stage of the\n * rendering pipeline. This function utilizes this event to flag potential root causes\n * to layout shifts.\n */\n async linkShiftsToLayoutInvalidations(\n layoutShifts: Types.TraceEvents.TraceEventLayoutShift[], modelData: TraceParseData): Promise<void> {\n const {prePaintEvents, layoutInvalidationEvents, scheduleStyleInvalidationEvents, backendNodeIds} =\n modelData.LayoutShifts;\n\n // For the purposes of determining root causes of layout shifts, we\n // consider scheduleStyleInvalidationTracking and\n // LayoutInvalidationTracking events as events that could have been the\n // cause of the layout shift.\n const eventsForLayoutInvalidation: Array<Types.TraceEvents.TraceEventLayoutInvalidationTracking|\n Types.TraceEvents.TraceEventScheduleStyleInvalidationTracking> =\n [...layoutInvalidationEvents, ...scheduleStyleInvalidationEvents];\n\n const nodes = await this.#protocolInterface.pushNodesByBackendIdsToFrontend(backendNodeIds);\n const nodeIdsByBackendIdMap = new Map<Protocol.DOM.BackendNodeId, Protocol.DOM.NodeId>();\n for (let i = 0; i < backendNodeIds.length; i++) {\n nodeIdsByBackendIdMap.set(backendNodeIds[i], nodes[i]);\n }\n\n // Maps from PrePaint events to LayoutShifts that occured in each one.\n const shiftsByPrePaint = getShiftsByPrePaintEvents(layoutShifts, prePaintEvents);\n for (const layoutInvalidation of eventsForLayoutInvalidation) {\n // Get the first PrePaint event that happened after the current LayoutInvalidation event.\n const nextPrePaintIndex = Platform.ArrayUtilities.nearestIndexFromBeginning(\n prePaintEvents, prePaint => prePaint.ts > layoutInvalidation.ts);\n if (nextPrePaintIndex === null) {\n // No PrePaint event registered after this LayoutInvalidation. Continue.\n continue;\n }\n const nextPrePaint = prePaintEvents[nextPrePaintIndex];\n const subsequentShifts = shiftsByPrePaint.get(nextPrePaint);\n if (!subsequentShifts) {\n // The PrePaint after the current LayoutInvalidation doesn't contain shifts.\n continue;\n }\n const fontChangeRootCause = this.getFontChangeRootCause(layoutInvalidation, nextPrePaint, modelData);\n const renderBlockRootCause = this.getRenderBlockRootCause(layoutInvalidation, nextPrePaint, modelData);\n const layoutInvalidationNodeId = nodeIdsByBackendIdMap.get(layoutInvalidation.args.data.nodeId);\n const layoutInvalidationNode = layoutInvalidationNodeId !== undefined ?\n await this.#protocolInterface.getNode(layoutInvalidationNodeId) :\n null;\n let unsizedMediaRootCause: UnsizedMedia|null = null;\n let iframeRootCause: InjectedIframe|null = null;\n if (layoutInvalidationNode && layoutInvalidation.args.data.reason) {\n unsizedMediaRootCause =\n await this.getUnsizedMediaRootCause(layoutInvalidation.args.data.reason, layoutInvalidationNode);\n iframeRootCause = this.getIframeRootCause(layoutInvalidation.args.data.reason, layoutInvalidationNode);\n }\n\n if (!unsizedMediaRootCause && !iframeRootCause && !fontChangeRootCause && !renderBlockRootCause) {\n continue;\n }\n\n // Add found potential root causes to all the shifts in this PrePaint and populate the cache.\n for (const shift of subsequentShifts) {\n const rootCausesForShift = Platform.MapUtilities.getWithDefault(this.#rootCauseCacheMap, shift, () => {\n return {\n unsizedMedia: [],\n iframes: [],\n fontChanges: [],\n renderBlockingRequests: [],\n scriptStackTrace: [],\n };\n });\n if (unsizedMediaRootCause &&\n !rootCausesForShift.unsizedMedia.some(media => media.node.nodeId === unsizedMediaRootCause?.node.nodeId) &&\n shift.args.frame === layoutInvalidation.args.data.frame) {\n rootCausesForShift.unsizedMedia.push(unsizedMediaRootCause);\n }\n if (iframeRootCause &&\n !rootCausesForShift.iframes.some(\n injectedIframe => injectedIframe.iframe.nodeId === iframeRootCause?.iframe.nodeId)) {\n rootCausesForShift.iframes.push(iframeRootCause);\n }\n if (fontChangeRootCause) {\n // Unlike other root causes, we calculate fonts causing a shift only once,\n // which means we assign the built array instead of appending new objects\n // to it.\n rootCausesForShift.fontChanges = fontChangeRootCause;\n }\n if (renderBlockRootCause) {\n rootCausesForShift.renderBlockingRequests = renderBlockRootCause;\n }\n }\n }\n }\n\n /**\n * For every shift looks up the initiator of its corresponding Layout event. This initiator\n * is assigned by the RendererHandler and contains the stack trace of the point in a script\n * that caused a style recalculation or a relayout. This stack trace is added to the shift's\n * potential root causes.\n * Note that a Layout cannot always be linked to a script, in that case, we cannot add a\n * \"script causing reflow\" as a potential root cause to the corresponding shift.\n */\n linkShiftsToLayoutEvents(layoutShifts: Types.TraceEvents.TraceEventLayoutShift[], modelData: TraceParseData): void {\n const {prePaintEvents} = modelData.LayoutShifts;\n // Maps from PrePaint events to LayoutShifts that occured in each one.\n const shiftsByPrePaint = getShiftsByPrePaintEvents(layoutShifts, prePaintEvents);\n\n const eventTriggersLayout = ({name}: {name: string}): boolean => {\n const knownName = name as Types.TraceEvents.KnownEventName;\n return knownName === Types.TraceEvents.KnownEventName.Layout;\n };\n const layoutEvents = modelData.Renderer.allTraceEntries.filter(eventTriggersLayout);\n for (const layout of layoutEvents) {\n // Get the first PrePaint event that happened after the current layout event.\n const nextPrePaintIndex = Platform.ArrayUtilities.nearestIndexFromBeginning(\n prePaintEvents, prePaint => prePaint.ts > layout.ts + (layout.dur || 0));\n if (nextPrePaintIndex === null) {\n // No PrePaint event registered after this LayoutInvalidation. Continue.\n continue;\n }\n const nextPrePaint = prePaintEvents[nextPrePaintIndex];\n const subsequentShifts = shiftsByPrePaint.get(nextPrePaint);\n if (!subsequentShifts) {\n // The PrePaint after the current LayoutInvalidation doesn't contain shifts.\n continue;\n }\n const layoutNode = modelData.Renderer.entryToNode.get(layout);\n const initiator = layoutNode ? modelData.Initiators.eventToInitiator.get(layoutNode.entry) : null;\n const stackTrace = initiator?.args?.data?.stackTrace;\n if (!stackTrace) {\n continue;\n }\n // Add found potential root causes to all the shifts in this PrePaint and populate the cache.\n for (const shift of subsequentShifts) {\n const rootCausesForShift = Platform.MapUtilities.getWithDefault(this.#rootCauseCacheMap, shift, () => {\n return {\n unsizedMedia: [],\n iframes: [],\n fontChanges: [],\n renderBlockingRequests: [],\n scriptStackTrace: [],\n };\n });\n if (rootCausesForShift.scriptStackTrace.length === 0) {\n rootCausesForShift.scriptStackTrace = stackTrace;\n }\n }\n }\n }\n\n /**\n * Given a LayoutInvalidation trace event, determines if it was dispatched\n * because a media element without dimensions was resized.\n */\n async getUnsizedMediaRootCause(\n reason: Types.TraceEvents.LayoutInvalidationReason,\n layoutInvalidationNode: Protocol.DOM.Node): Promise<UnsizedMedia|null> {\n // Filter events to resizes only.\n if (reason !== Types.TraceEvents.LayoutInvalidationReason.SIZE_CHANGED) {\n return null;\n }\n const computedStylesList = await this.#protocolInterface.getComputedStyleForNode(layoutInvalidationNode.nodeId);\n const computedStyles = new Map(computedStylesList.map(item => [item.name, item.value]));\n if (computedStyles && !(await nodeIsUnfixedMedia(layoutInvalidationNode, computedStyles))) {\n return null;\n }\n const authoredDimensions = await this.getNodeAuthoredDimensions(layoutInvalidationNode);\n if (dimensionsAreExplicit(authoredDimensions)) {\n return null;\n }\n const computedDimensions = computedStyles ? getNodeComputedDimensions(computedStyles) : {};\n\n return {node: layoutInvalidationNode, authoredDimensions, computedDimensions};\n }\n\n /**\n * Given a LayoutInvalidation trace event, determines if it was dispatched\n * because a node, which is an ancestor to an iframe, was injected.\n */\n getIframeRootCause(reason: Types.TraceEvents.LayoutInvalidationReason, layoutInvalidationDOMNode: Protocol.DOM.Node):\n InjectedIframe|null {\n if (layoutInvalidationDOMNode.nodeName !== 'IFRAME' &&\n reason !== Types.TraceEvents.LayoutInvalidationReason.STYLE_CHANGED &&\n reason !== Types.TraceEvents.LayoutInvalidationReason.ADDED_TO_LAYOUT) {\n return null;\n }\n const iframe = firstIframeInDOMTree(layoutInvalidationDOMNode);\n if (!iframe) {\n return null;\n }\n return {iframe};\n }\n\n /**\n * Given a layout invalidation event and a sorted array, returns the subset of requests that arrived within a\n * 500ms window before the layout invalidation.\n */\n requestsInInvalidationWindow(\n layoutInvalidation: Types.TraceEvents.TraceEventLayoutInvalidationTracking|\n Types.TraceEvents.TraceEventScheduleStyleInvalidationTracking,\n modelData: TraceParseData): RootCauseRequest[] {\n const requestsSortedByEndTime = modelData.NetworkRequests.byTime.sort((req1, req2) => {\n const req1EndTime = req1.ts + req1.dur;\n const req2EndTime = req2.ts + req2.dur;\n return req1EndTime - req2EndTime;\n });\n\n const lastRequestIndex = Platform.ArrayUtilities.nearestIndexFromEnd(\n requestsSortedByEndTime, request => request.ts + request.dur < layoutInvalidation.ts);\n if (lastRequestIndex === null) {\n return [];\n }\n\n const MAX_DELTA_FOR_FONT_REQUEST = Helpers.Timing.secondsToMicroseconds(Types.Timing.Seconds(0.5));\n\n const requestsInInvalidationWindow: RootCauseRequest[] = [];\n\n // Get all requests finished within the valid window.\n for (let i = lastRequestIndex; i > -1; i--) {\n const previousRequest = requestsSortedByEndTime[i];\n const previousRequestEndTime = previousRequest.ts + previousRequest.dur;\n if (layoutInvalidation.ts - previousRequestEndTime < MAX_DELTA_FOR_FONT_REQUEST) {\n const requestInInvalidationWindow: RootCauseRequest = {request: previousRequest};\n\n const initiator = this.#protocolInterface.getInitiatorForRequest(\n previousRequest.args.data.url as Platform.DevToolsPath.UrlString);\n requestInInvalidationWindow.initiator = initiator || undefined;\n requestsInInvalidationWindow.push(requestInInvalidationWindow);\n } else {\n // No more requests fit in the time window.\n break;\n }\n }\n return requestsInInvalidationWindow;\n }\n\n /**\n * Given a LayoutInvalidation trace event, determines if it was dispatched\n * because fonts were changed and if so returns the information of all network\n * request with which the fonts were possibly fetched, if any. The computed\n * network requests are cached for the corresponding prepaint event, meaning\n * that other LayoutInvalidation events that correspond to the same prepaint\n * are not processed and the cached network requests for the prepaint is\n * returned instead.\n */\n getFontChangeRootCause(\n layoutInvalidation: Types.TraceEvents.TraceEventLayoutInvalidationTracking|\n Types.TraceEvents.TraceEventScheduleStyleInvalidationTracking,\n nextPrePaint: Types.TraceEvents.TraceEventPrePaint, modelData: TraceParseData): FontChange[]|null {\n if (layoutInvalidation.args.data.reason !== Types.TraceEvents.LayoutInvalidationReason.FONTS_CHANGED) {\n return null;\n }\n // Prevent computing the result of this function multiple times per PrePaint event.\n const fontRequestsForPrepaint = fontRequestsByPrePaint.get(nextPrePaint);\n if (fontRequestsForPrepaint !== undefined) {\n return fontRequestsForPrepaint;\n }\n\n const fontRequestsInThisPrepaint =\n this.getFontRequestsInInvalidationWindow(this.requestsInInvalidationWindow(layoutInvalidation, modelData));\n fontRequestsByPrePaint.set(nextPrePaint, fontRequestsInThisPrepaint);\n return fontRequestsInThisPrepaint;\n }\n\n /**\n * Given the requests that arrived within a 500ms window before the layout invalidation, returns the font\n * requests of them.\n */\n getFontRequestsInInvalidationWindow(requestsInInvalidationWindow: RootCauseRequest[]): FontChange[] {\n const fontRequests: FontChange[] = [];\n\n // Get all requests finished within the valid window.\n for (let i = 0; i < requestsInInvalidationWindow.length; i++) {\n const fontRequest = requestsInInvalidationWindow[i] as FontChange;\n if (!fontRequest.request.args.data.mimeType.startsWith('font')) {\n continue;\n }\n\n const fontFace = this.#protocolInterface.fontFaceForSource(fontRequest.request.args.data.url);\n if (!fontFace || fontFace.fontDisplay === 'optional') {\n // Setting font-display to optional is part of what the developer\n // can do to avoid layout shifts due to FOIT/FOUT, as such we cannot\n // suggest any actionable insight here.\n continue;\n }\n fontRequest.fontFace = fontFace;\n fontRequests.push(fontRequest);\n }\n return fontRequests;\n }\n\n /**\n * Given a LayoutInvalidation trace event, determines if it arrived within a 500ms window before the layout\n * invalidation and if so returns the information of all network request, if any. The computed network\n * requests are cached for the corresponding prepaint event, meaning that other LayoutInvalidation events\n * that correspond to the same prepaint are not processed and the cached network requests for the prepaint is\n * returned instead.\n */\n getRenderBlockRootCause(\n layoutInvalidation: Types.TraceEvents.TraceEventLayoutInvalidationTracking|\n Types.TraceEvents.TraceEventScheduleStyleInvalidationTracking,\n nextPrePaint: Types.TraceEvents.TraceEventPrePaint, modelData: TraceParseData): RenderBlockingRequest[]|null {\n // Prevent computing the result of this function multiple times per PrePaint event.\n const renderBlocksInPrepaint = renderBlocksByPrePaint.get(nextPrePaint);\n if (renderBlocksInPrepaint !== undefined) {\n return renderBlocksInPrepaint;\n }\n\n const renderBlocksInThisPrepaint =\n getRenderBlockRequestsInInvalidationWindow(this.requestsInInvalidationWindow(layoutInvalidation, modelData));\n renderBlocksByPrePaint.set(nextPrePaint, renderBlocksInThisPrepaint);\n return renderBlocksInThisPrepaint;\n }\n\n /**\n * Returns a function that retrieves the active value of a given\n * CSS property within the matched styles of the param node.\n * The first occurence within the matched styles is returned and the\n * value is looked up in the following order, which follows CSS\n * specificity:\n * 1. Inline styles.\n * 2. CSS rules matching this node, from all applicable stylesheets.\n * 3. Attribute defined styles.\n */\n async nodeMatchedStylesPropertyGetter(node: Protocol.DOM.Node): Promise<((property: string) => string | null)> {\n const response = await this.#protocolInterface.getMatchedStylesForNode(node.nodeId);\n\n function cssPropertyValueGetter(cssProperty: string): string|null {\n let prop = response.inlineStyle?.cssProperties.find(prop => prop.name === cssProperty);\n if (prop) {\n return prop.value;\n }\n\n for (const {rule} of response.matchedCSSRules || []) {\n const prop = rule.style.cssProperties.find(prop => prop.name === cssProperty);\n if (prop) {\n return prop.value;\n }\n }\n\n prop = response.attributesStyle?.cssProperties.find(prop => prop.name === cssProperty);\n if (prop) {\n return prop.value;\n }\n\n return null;\n }\n return cssPropertyValueGetter;\n }\n\n /**\n * Returns the CSS dimensions set to the node from its matched styles.\n */\n async getNodeAuthoredDimensions(node: Protocol.DOM.Node): Promise<CSSDimensions> {\n const authoredDimensions: CSSDimensions = {};\n\n const cssMatchedRulesGetter = await this.nodeMatchedStylesPropertyGetter(node);\n if (!cssMatchedRulesGetter) {\n return authoredDimensions;\n }\n\n const attributesFlat = node.attributes || [];\n const attributes = [];\n for (let i = 0; i < attributesFlat.length; i += 2) {\n attributes.push({name: attributesFlat[i], value: attributesFlat[i + 1]});\n }\n\n const htmlHeight = attributes.find(attr => attr.name === 'height' && htmlAttributeIsExplicit(attr));\n const htmlWidth = attributes.find(attr => attr.name === 'width' && htmlAttributeIsExplicit(attr));\n\n const cssExplicitAspectRatio = cssMatchedRulesGetter('aspect-ratio') || undefined;\n\n if (htmlHeight && htmlWidth && cssExplicitAspectRatio) {\n return {height: htmlHeight.value, width: htmlWidth.value, aspectRatio: cssExplicitAspectRatio};\n }\n\n const cssHeight = cssMatchedRulesGetter('height') || undefined;\n const cssWidth = cssMatchedRulesGetter('width') || undefined;\n return {height: cssHeight, width: cssWidth, aspectRatio: cssExplicitAspectRatio};\n }\n}\n\n/**\n * Given the requests that arrived within a 500ms window before the layout invalidation, returns the render\n * block requests of them.\n */\nfunction getRenderBlockRequestsInInvalidationWindow(requestsInInvalidationWindow: RootCauseRequest[]):\n RenderBlockingRequest[] {\n const renderBlockingRequests: RenderBlockingRequest[] = [];\n\n // Get all requests finished within the valid window.\n for (let i = 0; i < requestsInInvalidationWindow.length; i++) {\n const mainFrameId = requestsInInvalidationWindow[i].request.args.data.frame;\n if (!networkRequestIsRenderBlockingInFrame(requestsInInvalidationWindow[i].request, mainFrameId)) {\n continue;\n }\n renderBlockingRequests.push(requestsInInvalidationWindow[i] as RenderBlockingRequest);\n }\n return renderBlockingRequests;\n}\n\nfunction firstIframeInDOMTree(root: Protocol.DOM.Node): Protocol.DOM.Node|null {\n if (root.nodeName === 'IFRAME') {\n return root;\n }\n const children = root.children;\n if (!children) {\n return null;\n }\n for (const child of children) {\n const iFrameInChild = firstIframeInDOMTree(child);\n if (iFrameInChild) {\n return iFrameInChild;\n }\n }\n return null;\n}\n\nfunction cssPropertyIsExplicitlySet(propertyValue: string): boolean {\n return !['auto', 'initial', 'unset', 'inherit'].includes(propertyValue);\n}\n\nfunction htmlAttributeIsExplicit(attr: {value: string}): boolean {\n return parseInt(attr.value, 10) >= 0;\n}\n\nfunction computedStyleHasBackroundImage(computedStyle: Map<string, string>): boolean {\n const CSS_URL_REGEX = /^url\\(\"([^\"]+)\"\\)$/;\n const backgroundImage = computedStyle.get('background-image');\n if (!backgroundImage) {\n return false;\n }\n return CSS_URL_REGEX.test(backgroundImage);\n}\n\nfunction computedStyleHasFixedPosition(computedStyle: Map<string, string>): boolean {\n const position = computedStyle.get('position');\n if (!position) {\n return false;\n }\n return position === 'fixed' || position === 'absolute';\n}\n\nfunction getNodeComputedDimensions(computedStyle: Map<string, string>): CSSDimensions {\n const computedDimensions: CSSDimensions = {};\n computedDimensions.height = computedStyle.get('height');\n computedDimensions.width = computedStyle.get('width');\n computedDimensions.aspectRatio = computedStyle.get('aspect-ratio');\n return computedDimensions;\n}\n\n/**\n * Determines if a node is a media element and is not fixed positioned\n * (i.e. \"position: fixed;\" or \"position: absolute;\")\n */\nasync function nodeIsUnfixedMedia(node: Protocol.DOM.Node, computedStyle: Map<string, string>): Promise<boolean> {\n const localName = node.localName;\n const isBackgroundImage = computedStyleHasBackroundImage(computedStyle);\n if (localName !== 'img' && localName !== 'video' && !isBackgroundImage) {\n // Not a media element.\n return false;\n }\n const isFixed = computedStyleHasFixedPosition(computedStyle);\n return !isFixed;\n}\n\n/**\n * Determines if a CSS dimensions object explicitly defines both width and height\n * (i.e. not set to auto, inherit, etc.)\n */\nfunction dimensionsAreExplicit(dimensions: CSSDimensions): boolean {\n const {height, width, aspectRatio} = dimensions;\n\n const explicitHeight = Boolean(height && cssPropertyIsExplicitlySet(height));\n const explicitWidth = Boolean(width && cssPropertyIsExplicitlySet(width));\n const explicitAspectRatio = Boolean(aspectRatio && cssPropertyIsExplicitlySet(aspectRatio));\n\n const explicitWithAR = (explicitHeight || explicitWidth) && explicitAspectRatio;\n return (explicitHeight && explicitWidth) || explicitWithAR;\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.TraceEvents.TraceEventLayoutShift[],\n prePaintEvents: Types.TraceEvents.TraceEventPrePaint[],\n ): Map<Types.TraceEvents.TraceEventPrePaint, Types.TraceEvents.TraceEventLayoutShift[]> {\n // Maps from PrePaint events to LayoutShifts that occured in each one.\n const shiftsByPrePaint = new Map<Types.TraceEvents.TraceEventPrePaint, Types.TraceEvents.TraceEventLayoutShift[]>();\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 the end of this PrePaint. Continue to the next one.\n break;\n }\n }\n }\n return shiftsByPrePaint;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"LayoutShift.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/root-causes/LayoutShift.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2023 The Chromium Authors. All rights reserved.\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 Platform from '../../../core/platform/platform.js';\nimport type * as Protocol from '../../../generated/protocol.js';\nimport {type TraceParseData} from '../handlers/types.js';\nimport * as Helpers from '../helpers/helpers.js';\nimport * as Types from '../types/types.js';\n\nimport {type RootCauseProtocolInterface} from './RootCauses.js';\n\nexport type CSSDimensions = {\n width?: string,\n height?: string,\n aspectRatio?: string,\n};\n\nexport interface UnsizedMedia {\n node: Protocol.DOM.Node;\n authoredDimensions?: CSSDimensions;\n computedDimensions: CSSDimensions;\n}\n\nexport interface InjectedIframe {\n iframe: Protocol.DOM.Node;\n}\n\nexport interface RootCauseRequest {\n request: Types.TraceEvents.SyntheticNetworkRequest;\n initiator?: Protocol.Network.Initiator;\n}\n\nexport interface FontChange extends RootCauseRequest {\n fontFace: Protocol.CSS.FontFace;\n}\n\nexport interface RenderBlockingRequest extends RootCauseRequest {}\n\nexport interface LayoutShiftRootCausesData {\n unsizedMedia: UnsizedMedia[];\n iframes: InjectedIframe[];\n fontChanges: FontChange[];\n renderBlockingRequests: RenderBlockingRequest[];\n scriptStackTrace: Types.TraceEvents.TraceEventCallFrame[];\n}\n\nconst fontRequestsByPrePaint = new Map<Types.TraceEvents.TraceEventPrePaint, FontChange[]|null>();\nconst renderBlocksByPrePaint = new Map<Types.TraceEvents.TraceEventPrePaint, RenderBlockingRequest[]|null>();\n\nfunction setDefaultValue(\n map: Map<Types.TraceEvents.TraceEventLayoutShift, LayoutShiftRootCausesData>,\n shift: Types.TraceEvents.TraceEventLayoutShift): void {\n Platform.MapUtilities.getWithDefault(map, shift, () => {\n return {\n unsizedMedia: [],\n iframes: [],\n fontChanges: [],\n renderBlockingRequests: [],\n scriptStackTrace: [],\n };\n });\n}\n\n// Important: we purposefully treat `potentially_blocking` as\n// non-render-blocking here because:\n// 1. An async script can run on the main thread at any point, including before\n// the page is loaded\n// 2. An async script will never block the parsing and rendering process of the\n// browser.\n// 3. Therefore, from a developer's point of view, there is nothing more they\n// can do if they've put `async` on, and within the context of Insights, we\n// shouldn't report an async script as render blocking.\n// In the future we may want to consider suggesting the use of `defer` over\n// `async`, as it doesn't have this concern, but for now we'll allow `async`\n// and not report it as an issue.\nconst NON_RENDER_BLOCKING_VALUES = new Set<Types.TraceEvents.RenderBlocking>([\n 'non_blocking',\n 'potentially_blocking',\n]);\nfunction networkRequestIsRenderBlockingInFrame(\n event: Types.TraceEvents.SyntheticNetworkRequest, frameId: string): boolean {\n const isRenderBlocking = !NON_RENDER_BLOCKING_VALUES.has(event.args.data.renderBlocking);\n return isRenderBlocking && event.args.data.frame === frameId;\n}\n\nexport class LayoutShiftRootCauses {\n #protocolInterface: RootCauseProtocolInterface;\n #rootCauseCacheMap = new Map<Types.TraceEvents.TraceEventLayoutShift, LayoutShiftRootCausesData>();\n\n constructor(protocolInterface: RootCauseProtocolInterface) {\n this.#protocolInterface = protocolInterface;\n }\n\n /**\n * Calculates the potential root causes for a given layout shift event. Once\n * calculated, this data is cached.\n * Note: because you need all layout shift data at once to calculate these\n * correctly, this function will parse the root causes for _all_ layout shift\n * events the first time that it's called. That then populates the cache for\n * each shift, so any subsequent calls are just a constant lookup.\n */\n async rootCausesForEvent(modelData: TraceParseData, event: Types.TraceEvents.TraceEventLayoutShift):\n Promise<Readonly<LayoutShiftRootCausesData>|null> {\n const cachedResult = this.#rootCauseCacheMap.get(event);\n if (cachedResult) {\n return cachedResult;\n }\n\n const allLayoutShifts = modelData.LayoutShifts.clusters.flatMap(cluster => cluster.events);\n // Make sure a value in the cache is set even for shifts that don't have a root cause,\n // so that we don't have to recompute when no root causes are found. In case a cause\n // for a shift is found, the default value is replaced.\n allLayoutShifts.forEach(shift => setDefaultValue(this.#rootCauseCacheMap, shift));\n\n // Populate the cache\n await this.blameShifts(\n allLayoutShifts,\n modelData,\n );\n\n const resultForEvent = this.#rootCauseCacheMap.get(event);\n if (!resultForEvent) {\n // No root causes available for this layout shift.\n return null;\n }\n return resultForEvent;\n }\n\n /**\n * Determines potential root causes for shifts\n */\n async blameShifts(\n layoutShifts: Types.TraceEvents.TraceEventLayoutShift[],\n modelData: TraceParseData,\n ): Promise<void> {\n await this.linkShiftsToLayoutInvalidations(layoutShifts, modelData);\n this.linkShiftsToLayoutEvents(layoutShifts, modelData);\n }\n\n /**\n * \"LayoutInvalidations\" are a set of trace events dispatched in Blink under the name\n * \"layoutInvalidationTracking\", which track invalidations on the \"Layout\"stage of the\n * rendering pipeline. This function utilizes this event to flag potential root causes\n * to layout shifts.\n */\n async linkShiftsToLayoutInvalidations(\n layoutShifts: Types.TraceEvents.TraceEventLayoutShift[], modelData: TraceParseData): Promise<void> {\n const {prePaintEvents, layoutInvalidationEvents, scheduleStyleInvalidationEvents, backendNodeIds} =\n modelData.LayoutShifts;\n\n // For the purposes of determining root causes of layout shifts, we\n // consider scheduleStyleInvalidationTracking and\n // LayoutInvalidationTracking events as events that could have been the\n // cause of the layout shift.\n const eventsForLayoutInvalidation: Array<Types.TraceEvents.TraceEventLayoutInvalidationTracking|\n Types.TraceEvents.TraceEventScheduleStyleInvalidationTracking> =\n [...layoutInvalidationEvents, ...scheduleStyleInvalidationEvents];\n\n const nodes = await this.#protocolInterface.pushNodesByBackendIdsToFrontend(backendNodeIds);\n const nodeIdsByBackendIdMap = new Map<Protocol.DOM.BackendNodeId, Protocol.DOM.NodeId>();\n for (let i = 0; i < backendNodeIds.length; i++) {\n nodeIdsByBackendIdMap.set(backendNodeIds[i], nodes[i]);\n }\n\n // Maps from PrePaint events to LayoutShifts that occured in each one.\n const shiftsByPrePaint = getShiftsByPrePaintEvents(layoutShifts, prePaintEvents);\n for (const layoutInvalidation of eventsForLayoutInvalidation) {\n // Get the first PrePaint event that happened after the current LayoutInvalidation event.\n const nextPrePaintIndex = Platform.ArrayUtilities.nearestIndexFromBeginning(\n prePaintEvents, prePaint => prePaint.ts > layoutInvalidation.ts);\n if (nextPrePaintIndex === null) {\n // No PrePaint event registered after this LayoutInvalidation. Continue.\n continue;\n }\n const nextPrePaint = prePaintEvents[nextPrePaintIndex];\n const subsequentShifts = shiftsByPrePaint.get(nextPrePaint);\n if (!subsequentShifts) {\n // The PrePaint after the current LayoutInvalidation doesn't contain shifts.\n continue;\n }\n const fontChangeRootCause = this.getFontChangeRootCause(layoutInvalidation, nextPrePaint, modelData);\n const renderBlockRootCause = this.getRenderBlockRootCause(layoutInvalidation, nextPrePaint, modelData);\n const layoutInvalidationNodeId = nodeIdsByBackendIdMap.get(layoutInvalidation.args.data.nodeId);\n let unsizedMediaRootCause: UnsizedMedia|null = null;\n let iframeRootCause: InjectedIframe|null = null;\n if (layoutInvalidationNodeId !== undefined &&\n Types.TraceEvents.isTraceEventLayoutInvalidationTracking(layoutInvalidation)) {\n unsizedMediaRootCause = await this.getUnsizedMediaRootCause(layoutInvalidation, layoutInvalidationNodeId);\n iframeRootCause = await this.getIframeRootCause(layoutInvalidation, layoutInvalidationNodeId);\n }\n\n if (!unsizedMediaRootCause && !iframeRootCause && !fontChangeRootCause && !renderBlockRootCause) {\n continue;\n }\n\n // Add found potential root causes to all the shifts in this PrePaint and populate the cache.\n for (const shift of subsequentShifts) {\n const rootCausesForShift = Platform.MapUtilities.getWithDefault(this.#rootCauseCacheMap, shift, () => {\n return {\n unsizedMedia: [],\n iframes: [],\n fontChanges: [],\n renderBlockingRequests: [],\n scriptStackTrace: [],\n };\n });\n if (unsizedMediaRootCause &&\n !rootCausesForShift.unsizedMedia.some(media => media.node.nodeId === unsizedMediaRootCause?.node.nodeId) &&\n shift.args.frame === layoutInvalidation.args.data.frame) {\n rootCausesForShift.unsizedMedia.push(unsizedMediaRootCause);\n }\n if (iframeRootCause &&\n !rootCausesForShift.iframes.some(\n injectedIframe => injectedIframe.iframe.nodeId === iframeRootCause?.iframe.nodeId)) {\n rootCausesForShift.iframes.push(iframeRootCause);\n }\n if (fontChangeRootCause) {\n // Unlike other root causes, we calculate fonts causing a shift only once,\n // which means we assign the built array instead of appending new objects\n // to it.\n rootCausesForShift.fontChanges = fontChangeRootCause;\n }\n if (renderBlockRootCause) {\n rootCausesForShift.renderBlockingRequests = renderBlockRootCause;\n }\n }\n }\n }\n\n /**\n * For every shift looks up the initiator of its corresponding Layout event. This initiator\n * is assigned by the RendererHandler and contains the stack trace of the point in a script\n * that caused a style recalculation or a relayout. This stack trace is added to the shift's\n * potential root causes.\n * Note that a Layout cannot always be linked to a script, in that case, we cannot add a\n * \"script causing reflow\" as a potential root cause to the corresponding shift.\n */\n linkShiftsToLayoutEvents(layoutShifts: Types.TraceEvents.TraceEventLayoutShift[], modelData: TraceParseData): void {\n const {prePaintEvents} = modelData.LayoutShifts;\n // Maps from PrePaint events to LayoutShifts that occured in each one.\n const shiftsByPrePaint = getShiftsByPrePaintEvents(layoutShifts, prePaintEvents);\n\n const eventTriggersLayout = ({name}: {name: string}): boolean => {\n const knownName = name as Types.TraceEvents.KnownEventName;\n return knownName === Types.TraceEvents.KnownEventName.Layout;\n };\n const layoutEvents = modelData.Renderer.allTraceEntries.filter(eventTriggersLayout);\n for (const layout of layoutEvents) {\n // Get the first PrePaint event that happened after the current layout event.\n const nextPrePaintIndex = Platform.ArrayUtilities.nearestIndexFromBeginning(\n prePaintEvents, prePaint => prePaint.ts > layout.ts + (layout.dur || 0));\n if (nextPrePaintIndex === null) {\n // No PrePaint event registered after this LayoutInvalidation. Continue.\n continue;\n }\n const nextPrePaint = prePaintEvents[nextPrePaintIndex];\n const subsequentShifts = shiftsByPrePaint.get(nextPrePaint);\n if (!subsequentShifts) {\n // The PrePaint after the current LayoutInvalidation doesn't contain shifts.\n continue;\n }\n const layoutNode = modelData.Renderer.entryToNode.get(layout);\n const initiator = layoutNode ? modelData.Initiators.eventToInitiator.get(layoutNode.entry) : null;\n const stackTrace = initiator?.args?.data?.stackTrace;\n if (!stackTrace) {\n continue;\n }\n // Add found potential root causes to all the shifts in this PrePaint and populate the cache.\n for (const shift of subsequentShifts) {\n const rootCausesForShift = Platform.MapUtilities.getWithDefault(this.#rootCauseCacheMap, shift, () => {\n return {\n unsizedMedia: [],\n iframes: [],\n fontChanges: [],\n renderBlockingRequests: [],\n scriptStackTrace: [],\n };\n });\n if (rootCausesForShift.scriptStackTrace.length === 0) {\n rootCausesForShift.scriptStackTrace = stackTrace;\n }\n }\n }\n }\n\n /**\n * Given a LayoutInvalidation trace event, determines if it was dispatched\n * because a media element without dimensions was resized.\n */\n async getUnsizedMediaRootCause(\n layoutInvalidation: Types.TraceEvents.TraceEventLayoutInvalidationTracking,\n layoutInvalidationNodeId: Protocol.DOM.NodeId): Promise<UnsizedMedia|null> {\n // Filter events to resizes only.\n if (layoutInvalidation.args.data.reason !== Types.TraceEvents.LayoutInvalidationReason.SIZE_CHANGED) {\n return null;\n }\n\n const layoutInvalidationNode = await this.#protocolInterface.getNode(layoutInvalidationNodeId);\n if (!layoutInvalidationNode) {\n return null;\n }\n\n const computedStylesList = await this.#protocolInterface.getComputedStyleForNode(layoutInvalidationNode.nodeId);\n const computedStyles = new Map(computedStylesList.map(item => [item.name, item.value]));\n if (computedStyles && !(await nodeIsUnfixedMedia(layoutInvalidationNode, computedStyles))) {\n return null;\n }\n const authoredDimensions = await this.getNodeAuthoredDimensions(layoutInvalidationNode);\n if (dimensionsAreExplicit(authoredDimensions)) {\n return null;\n }\n const computedDimensions = computedStyles ? getNodeComputedDimensions(computedStyles) : {};\n\n return {node: layoutInvalidationNode, authoredDimensions, computedDimensions};\n }\n\n /**\n * Given a LayoutInvalidation trace event, determines if it was dispatched\n * because a node, which is an ancestor to an iframe, was injected.\n */\n async getIframeRootCause(\n layoutInvalidation: Types.TraceEvents.TraceEventLayoutInvalidationTracking,\n layoutInvalidationNodeId: Protocol.DOM.NodeId): Promise<InjectedIframe|null> {\n if (layoutInvalidation.args.data.nodeName?.startsWith('IFRAME') &&\n layoutInvalidation.args.data.reason !== Types.TraceEvents.LayoutInvalidationReason.STYLE_CHANGED &&\n layoutInvalidation.args.data.reason !== Types.TraceEvents.LayoutInvalidationReason.ADDED_TO_LAYOUT) {\n return null;\n }\n\n const layoutInvalidationNode = await this.#protocolInterface.getNode(layoutInvalidationNodeId);\n if (!layoutInvalidationNode) {\n return null;\n }\n\n const iframe = firstIframeInDOMTree(layoutInvalidationNode);\n if (!iframe) {\n return null;\n }\n return {iframe};\n }\n\n /**\n * Given a layout invalidation event and a sorted array, returns the subset of requests that arrived within a\n * 500ms window before the layout invalidation.\n */\n requestsInInvalidationWindow(\n layoutInvalidation: Types.TraceEvents.TraceEventLayoutInvalidationTracking|\n Types.TraceEvents.TraceEventScheduleStyleInvalidationTracking,\n modelData: TraceParseData): RootCauseRequest[] {\n const requestsSortedByEndTime = modelData.NetworkRequests.byTime.sort((req1, req2) => {\n const req1EndTime = req1.ts + req1.dur;\n const req2EndTime = req2.ts + req2.dur;\n return req1EndTime - req2EndTime;\n });\n\n const lastRequestIndex = Platform.ArrayUtilities.nearestIndexFromEnd(\n requestsSortedByEndTime, request => request.ts + request.dur < layoutInvalidation.ts);\n if (lastRequestIndex === null) {\n return [];\n }\n\n const MAX_DELTA_FOR_FONT_REQUEST = Helpers.Timing.secondsToMicroseconds(Types.Timing.Seconds(0.5));\n\n const requestsInInvalidationWindow: RootCauseRequest[] = [];\n\n // Get all requests finished within the valid window.\n for (let i = lastRequestIndex; i > -1; i--) {\n const previousRequest = requestsSortedByEndTime[i];\n const previousRequestEndTime = previousRequest.ts + previousRequest.dur;\n if (layoutInvalidation.ts - previousRequestEndTime < MAX_DELTA_FOR_FONT_REQUEST) {\n const requestInInvalidationWindow: RootCauseRequest = {request: previousRequest};\n\n const initiator = this.#protocolInterface.getInitiatorForRequest(\n previousRequest.args.data.url as Platform.DevToolsPath.UrlString);\n requestInInvalidationWindow.initiator = initiator || undefined;\n requestsInInvalidationWindow.push(requestInInvalidationWindow);\n } else {\n // No more requests fit in the time window.\n break;\n }\n }\n return requestsInInvalidationWindow;\n }\n\n /**\n * Given a LayoutInvalidation trace event, determines if it was dispatched\n * because fonts were changed and if so returns the information of all network\n * request with which the fonts were possibly fetched, if any. The computed\n * network requests are cached for the corresponding prepaint event, meaning\n * that other LayoutInvalidation events that correspond to the same prepaint\n * are not processed and the cached network requests for the prepaint is\n * returned instead.\n */\n getFontChangeRootCause(\n layoutInvalidation: Types.TraceEvents.TraceEventLayoutInvalidationTracking|\n Types.TraceEvents.TraceEventScheduleStyleInvalidationTracking,\n nextPrePaint: Types.TraceEvents.TraceEventPrePaint, modelData: TraceParseData): FontChange[]|null {\n if (layoutInvalidation.args.data.reason !== Types.TraceEvents.LayoutInvalidationReason.FONTS_CHANGED) {\n return null;\n }\n // Prevent computing the result of this function multiple times per PrePaint event.\n const fontRequestsForPrepaint = fontRequestsByPrePaint.get(nextPrePaint);\n if (fontRequestsForPrepaint !== undefined) {\n return fontRequestsForPrepaint;\n }\n\n const fontRequestsInThisPrepaint =\n this.getFontRequestsInInvalidationWindow(this.requestsInInvalidationWindow(layoutInvalidation, modelData));\n fontRequestsByPrePaint.set(nextPrePaint, fontRequestsInThisPrepaint);\n return fontRequestsInThisPrepaint;\n }\n\n /**\n * Given the requests that arrived within a 500ms window before the layout invalidation, returns the font\n * requests of them.\n */\n getFontRequestsInInvalidationWindow(requestsInInvalidationWindow: RootCauseRequest[]): FontChange[] {\n const fontRequests: FontChange[] = [];\n\n // Get all requests finished within the valid window.\n for (let i = 0; i < requestsInInvalidationWindow.length; i++) {\n const fontRequest = requestsInInvalidationWindow[i] as FontChange;\n if (!fontRequest.request.args.data.mimeType.startsWith('font')) {\n continue;\n }\n\n const fontFace = this.#protocolInterface.fontFaceForSource(fontRequest.request.args.data.url);\n if (!fontFace || fontFace.fontDisplay === 'optional') {\n // Setting font-display to optional is part of what the developer\n // can do to avoid layout shifts due to FOIT/FOUT, as such we cannot\n // suggest any actionable insight here.\n continue;\n }\n fontRequest.fontFace = fontFace;\n fontRequests.push(fontRequest);\n }\n return fontRequests;\n }\n\n /**\n * Given a LayoutInvalidation trace event, determines if it arrived within a 500ms window before the layout\n * invalidation and if so returns the information of all network request, if any. The computed network\n * requests are cached for the corresponding prepaint event, meaning that other LayoutInvalidation events\n * that correspond to the same prepaint are not processed and the cached network requests for the prepaint is\n * returned instead.\n */\n getRenderBlockRootCause(\n layoutInvalidation: Types.TraceEvents.TraceEventLayoutInvalidationTracking|\n Types.TraceEvents.TraceEventScheduleStyleInvalidationTracking,\n nextPrePaint: Types.TraceEvents.TraceEventPrePaint, modelData: TraceParseData): RenderBlockingRequest[]|null {\n // Prevent computing the result of this function multiple times per PrePaint event.\n const renderBlocksInPrepaint = renderBlocksByPrePaint.get(nextPrePaint);\n if (renderBlocksInPrepaint !== undefined) {\n return renderBlocksInPrepaint;\n }\n\n const renderBlocksInThisPrepaint =\n getRenderBlockRequestsInInvalidationWindow(this.requestsInInvalidationWindow(layoutInvalidation, modelData));\n renderBlocksByPrePaint.set(nextPrePaint, renderBlocksInThisPrepaint);\n return renderBlocksInThisPrepaint;\n }\n\n /**\n * Returns a function that retrieves the active value of a given\n * CSS property within the matched styles of the param node.\n * The first occurence within the matched styles is returned and the\n * value is looked up in the following order, which follows CSS\n * specificity:\n * 1. Inline styles.\n * 2. CSS rules matching this node, from all applicable stylesheets.\n * 3. Attribute defined styles.\n */\n async nodeMatchedStylesPropertyGetter(node: Protocol.DOM.Node): Promise<((property: string) => string | null)> {\n const response = await this.#protocolInterface.getMatchedStylesForNode(node.nodeId);\n\n function cssPropertyValueGetter(cssProperty: string): string|null {\n let prop = response.inlineStyle?.cssProperties.find(prop => prop.name === cssProperty);\n if (prop) {\n return prop.value;\n }\n\n for (const {rule} of response.matchedCSSRules || []) {\n const prop = rule.style.cssProperties.find(prop => prop.name === cssProperty);\n if (prop) {\n return prop.value;\n }\n }\n\n prop = response.attributesStyle?.cssProperties.find(prop => prop.name === cssProperty);\n if (prop) {\n return prop.value;\n }\n\n return null;\n }\n return cssPropertyValueGetter;\n }\n\n /**\n * Returns the CSS dimensions set to the node from its matched styles.\n */\n async getNodeAuthoredDimensions(node: Protocol.DOM.Node): Promise<CSSDimensions> {\n const authoredDimensions: CSSDimensions = {};\n\n const cssMatchedRulesGetter = await this.nodeMatchedStylesPropertyGetter(node);\n if (!cssMatchedRulesGetter) {\n return authoredDimensions;\n }\n\n const attributesFlat = node.attributes || [];\n const attributes = [];\n for (let i = 0; i < attributesFlat.length; i += 2) {\n attributes.push({name: attributesFlat[i], value: attributesFlat[i + 1]});\n }\n\n const htmlHeight = attributes.find(attr => attr.name === 'height' && htmlAttributeIsExplicit(attr));\n const htmlWidth = attributes.find(attr => attr.name === 'width' && htmlAttributeIsExplicit(attr));\n\n const cssExplicitAspectRatio = cssMatchedRulesGetter('aspect-ratio') || undefined;\n\n if (htmlHeight && htmlWidth && cssExplicitAspectRatio) {\n return {height: htmlHeight.value, width: htmlWidth.value, aspectRatio: cssExplicitAspectRatio};\n }\n\n const cssHeight = cssMatchedRulesGetter('height') || undefined;\n const cssWidth = cssMatchedRulesGetter('width') || undefined;\n return {height: cssHeight, width: cssWidth, aspectRatio: cssExplicitAspectRatio};\n }\n}\n\n/**\n * Given the requests that arrived within a 500ms window before the layout invalidation, returns the render\n * block requests of them.\n */\nfunction getRenderBlockRequestsInInvalidationWindow(requestsInInvalidationWindow: RootCauseRequest[]):\n RenderBlockingRequest[] {\n const renderBlockingRequests: RenderBlockingRequest[] = [];\n\n // Get all requests finished within the valid window.\n for (let i = 0; i < requestsInInvalidationWindow.length; i++) {\n const mainFrameId = requestsInInvalidationWindow[i].request.args.data.frame;\n if (!networkRequestIsRenderBlockingInFrame(requestsInInvalidationWindow[i].request, mainFrameId)) {\n continue;\n }\n renderBlockingRequests.push(requestsInInvalidationWindow[i] as RenderBlockingRequest);\n }\n return renderBlockingRequests;\n}\n\nfunction firstIframeInDOMTree(root: Protocol.DOM.Node): Protocol.DOM.Node|null {\n if (root.nodeName === 'IFRAME') {\n return root;\n }\n const children = root.children;\n if (!children) {\n return null;\n }\n for (const child of children) {\n const iFrameInChild = firstIframeInDOMTree(child);\n if (iFrameInChild) {\n return iFrameInChild;\n }\n }\n return null;\n}\n\nfunction cssPropertyIsExplicitlySet(propertyValue: string): boolean {\n return !['auto', 'initial', 'unset', 'inherit'].includes(propertyValue);\n}\n\nfunction htmlAttributeIsExplicit(attr: {value: string}): boolean {\n return parseInt(attr.value, 10) >= 0;\n}\n\nfunction computedStyleHasBackroundImage(computedStyle: Map<string, string>): boolean {\n const CSS_URL_REGEX = /^url\\(\"([^\"]+)\"\\)$/;\n const backgroundImage = computedStyle.get('background-image');\n if (!backgroundImage) {\n return false;\n }\n return CSS_URL_REGEX.test(backgroundImage);\n}\n\nfunction computedStyleHasFixedPosition(computedStyle: Map<string, string>): boolean {\n const position = computedStyle.get('position');\n if (!position) {\n return false;\n }\n return position === 'fixed' || position === 'absolute';\n}\n\nfunction getNodeComputedDimensions(computedStyle: Map<string, string>): CSSDimensions {\n const computedDimensions: CSSDimensions = {};\n computedDimensions.height = computedStyle.get('height');\n computedDimensions.width = computedStyle.get('width');\n computedDimensions.aspectRatio = computedStyle.get('aspect-ratio');\n return computedDimensions;\n}\n\n/**\n * Determines if a node is a media element and is not fixed positioned\n * (i.e. \"position: fixed;\" or \"position: absolute;\")\n */\nasync function nodeIsUnfixedMedia(node: Protocol.DOM.Node, computedStyle: Map<string, string>): Promise<boolean> {\n const localName = node.localName;\n const isBackgroundImage = computedStyleHasBackroundImage(computedStyle);\n if (localName !== 'img' && localName !== 'video' && !isBackgroundImage) {\n // Not a media element.\n return false;\n }\n const isFixed = computedStyleHasFixedPosition(computedStyle);\n return !isFixed;\n}\n\n/**\n * Determines if a CSS dimensions object explicitly defines both width and height\n * (i.e. not set to auto, inherit, etc.)\n */\nfunction dimensionsAreExplicit(dimensions: CSSDimensions): boolean {\n const {height, width, aspectRatio} = dimensions;\n\n const explicitHeight = Boolean(height && cssPropertyIsExplicitlySet(height));\n const explicitWidth = Boolean(width && cssPropertyIsExplicitlySet(width));\n const explicitAspectRatio = Boolean(aspectRatio && cssPropertyIsExplicitlySet(aspectRatio));\n\n const explicitWithAR = (explicitHeight || explicitWidth) && explicitAspectRatio;\n return (explicitHeight && explicitWidth) || explicitWithAR;\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.TraceEvents.TraceEventLayoutShift[],\n prePaintEvents: Types.TraceEvents.TraceEventPrePaint[],\n ): Map<Types.TraceEvents.TraceEventPrePaint, Types.TraceEvents.TraceEventLayoutShift[]> {\n // Maps from PrePaint events to LayoutShifts that occured in each one.\n const shiftsByPrePaint = new Map<Types.TraceEvents.TraceEventPrePaint, Types.TraceEvents.TraceEventLayoutShift[]>();\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 the end of this PrePaint. Continue to the next one.\n break;\n }\n }\n }\n return shiftsByPrePaint;\n}\n"]}
|
|
@@ -3,7 +3,7 @@ import { LayoutShiftRootCauses } from './LayoutShift.js';
|
|
|
3
3
|
export type RootCauseProtocolInterface = {
|
|
4
4
|
getInitiatorForRequest(url: string): Protocol.Network.Initiator | null;
|
|
5
5
|
pushNodesByBackendIdsToFrontend(backendNodeIds: Protocol.DOM.BackendNodeId[]): Promise<Protocol.DOM.NodeId[]>;
|
|
6
|
-
getNode(nodeId: Protocol.DOM.NodeId): Promise<Protocol.DOM.Node>;
|
|
6
|
+
getNode(nodeId: Protocol.DOM.NodeId): Promise<Protocol.DOM.Node | null>;
|
|
7
7
|
getComputedStyleForNode(nodeId: Protocol.DOM.NodeId): Promise<Protocol.CSS.CSSComputedStyleProperty[]>;
|
|
8
8
|
getMatchedStylesForNode(nodeId: Protocol.DOM.NodeId): Promise<Protocol.CSS.GetMatchedStylesForNodeResponse>;
|
|
9
9
|
fontFaceForSource(url: string): Protocol.CSS.FontFace | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RootCauses.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/root-causes/RootCauses.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAI7B,OAAO,EAAC,qBAAqB,EAAC,MAAM,kBAAkB,CAAC;AAWvD,MAAM,OAAO,UAAU;IACZ,YAAY,CAAwB;IAE7C,YAAY,iBAA6C;QACvD,IAAI,CAAC,YAAY,GAAG,IAAI,qBAAqB,CAAC,iBAAiB,CAAC,CAAC;IACnE,CAAC;CACF","sourcesContent":["// Copyright 2023 The Chromium Authors. All rights reserved.\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 Protocol from '../../../generated/protocol.js';\n\nimport {LayoutShiftRootCauses} from './LayoutShift.js';\n\nexport type RootCauseProtocolInterface = {\n getInitiatorForRequest(url: string): Protocol.Network.Initiator|null,\n pushNodesByBackendIdsToFrontend(backendNodeIds: Protocol.DOM.BackendNodeId[]): Promise<Protocol.DOM.NodeId[]>,\n getNode(nodeId: Protocol.DOM.NodeId): Promise<Protocol.DOM.Node>,\n getComputedStyleForNode(nodeId: Protocol.DOM.NodeId): Promise<Protocol.CSS.CSSComputedStyleProperty[]>,\n getMatchedStylesForNode(nodeId: Protocol.DOM.NodeId): Promise<Protocol.CSS.GetMatchedStylesForNodeResponse>,\n fontFaceForSource(url: string): Protocol.CSS.FontFace|undefined,\n};\n\nexport class RootCauses {\n readonly layoutShifts: LayoutShiftRootCauses;\n\n constructor(protocolInterface: RootCauseProtocolInterface) {\n this.layoutShifts = new LayoutShiftRootCauses(protocolInterface);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"RootCauses.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/root-causes/RootCauses.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AAI7B,OAAO,EAAC,qBAAqB,EAAC,MAAM,kBAAkB,CAAC;AAWvD,MAAM,OAAO,UAAU;IACZ,YAAY,CAAwB;IAE7C,YAAY,iBAA6C;QACvD,IAAI,CAAC,YAAY,GAAG,IAAI,qBAAqB,CAAC,iBAAiB,CAAC,CAAC;IACnE,CAAC;CACF","sourcesContent":["// Copyright 2023 The Chromium Authors. All rights reserved.\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 Protocol from '../../../generated/protocol.js';\n\nimport {LayoutShiftRootCauses} from './LayoutShift.js';\n\nexport type RootCauseProtocolInterface = {\n getInitiatorForRequest(url: string): Protocol.Network.Initiator|null,\n pushNodesByBackendIdsToFrontend(backendNodeIds: Protocol.DOM.BackendNodeId[]): Promise<Protocol.DOM.NodeId[]>,\n getNode(nodeId: Protocol.DOM.NodeId): Promise<Protocol.DOM.Node|null>,\n getComputedStyleForNode(nodeId: Protocol.DOM.NodeId): Promise<Protocol.CSS.CSSComputedStyleProperty[]>,\n getMatchedStylesForNode(nodeId: Protocol.DOM.NodeId): Promise<Protocol.CSS.GetMatchedStylesForNodeResponse>,\n fontFaceForSource(url: string): Protocol.CSS.FontFace|undefined,\n};\n\nexport class RootCauses {\n readonly layoutShifts: LayoutShiftRootCauses;\n\n constructor(protocolInterface: RootCauseProtocolInterface) {\n this.layoutShifts = new LayoutShiftRootCauses(protocolInterface);\n }\n}\n"]}
|
|
@@ -8,8 +8,16 @@ export const DEFAULT = {
|
|
|
8
8
|
timelineShowAllEvents: false,
|
|
9
9
|
},
|
|
10
10
|
processing: {
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
/**
|
|
12
|
+
* We want to yield regularly to maintain responsiveness. If we yield too often, we're wasting idle time.
|
|
13
|
+
* We could do this by checking `performance.now()` regularly, but it's an expensive call in such a hot loop.
|
|
14
|
+
* `eventsPerChunk` is an approximated proxy metric.
|
|
15
|
+
* But how big a chunk? We're aiming for long tasks that are no smaller than 100ms and not bigger than 200ms.
|
|
16
|
+
* It's CPU dependent, so it should be calibrated on oldish hardware.
|
|
17
|
+
* Illustration of a previous change to `eventsPerChunk`: https://imgur.com/wzp8BnR
|
|
18
|
+
*/
|
|
19
|
+
eventsPerChunk: 50_000,
|
|
20
|
+
pauseDuration: 0,
|
|
13
21
|
},
|
|
14
22
|
};
|
|
15
23
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Configuration.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/types/Configuration.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AA4B7B,MAAM,CAAC,MAAM,OAAO,GAAkB;IACpC,QAAQ,EAAE,EAAE;IACZ,WAAW,EAAE;QACX,0BAA0B,EAAE,KAAK;QACjC,qBAAqB,EAAE,KAAK;KAC7B;IACD,UAAU,EAAE;
|
|
1
|
+
{"version":3,"file":"Configuration.js","sourceRoot":"","sources":["../../../../../../../front_end/models/trace/types/Configuration.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAC5D,yEAAyE;AACzE,6BAA6B;AA4B7B,MAAM,CAAC,MAAM,OAAO,GAAkB;IACpC,QAAQ,EAAE,EAAE;IACZ,WAAW,EAAE;QACX,0BAA0B,EAAE,KAAK;QACjC,qBAAqB,EAAE,KAAK;KAC7B;IACD,UAAU,EAAE;QAEV;;;;;;;WAOG;QACH,cAAc,EAAE,MAAM;QACtB,aAAa,EAAE,CAAC;KACjB;CACF,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAqB;IACpD,OAAO;QACL,qCAAqC,MAAM,CAAC,WAAW,CAAC,qBAAqB,EAAE;QAC/E,0CAA0C,MAAM,CAAC,WAAW,CAAC,0BAA0B,EAAE;KAC1F,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC","sourcesContent":["// Copyright 2023 The Chromium Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style license that can be\n// found in the LICENSE file.\n\nexport type Configuration = Readonly<{\n settings: {\n // Currently empty but defining here as we will migrate more settings into this.\n },\n experiments: {\n /**\n * Include V8 RCS in the timeline\n */\n timelineV8RuntimeCallStats: boolean,\n /**\n * Show all events: disable the default filtering which hides and excludes some events.\n */\n timelineShowAllEvents: boolean,\n },\n processing: {\n /**\n * How long the processor should pause between event chunks.\n */\n pauseDuration: number,\n /**\n * How many events should be processed before yielding to the main thread for a pause.\n */\n eventsPerChunk: number,\n },\n}>;\n\nexport const DEFAULT: Configuration = {\n settings: {},\n experiments: {\n timelineV8RuntimeCallStats: false,\n timelineShowAllEvents: false,\n },\n processing: {\n\n /**\n * We want to yield regularly to maintain responsiveness. If we yield too often, we're wasting idle time.\n * We could do this by checking `performance.now()` regularly, but it's an expensive call in such a hot loop.\n * `eventsPerChunk` is an approximated proxy metric.\n * But how big a chunk? We're aiming for long tasks that are no smaller than 100ms and not bigger than 200ms.\n * It's CPU dependent, so it should be calibrated on oldish hardware.\n * Illustration of a previous change to `eventsPerChunk`: https://imgur.com/wzp8BnR\n */\n eventsPerChunk: 50_000,\n pauseDuration: 0,\n },\n};\n\n/**\n * Generates a key that can be used to represent this config in a cache. This is\n * used mainly in tests, where we want to avoid re-parsing a file if we have\n * already processed it with the same configuration. This cache key purposefully\n * does not include all settings in the configuration; the processing settings\n * do not impact the actual resulting data. Only new flags in the config that\n * alter parsing should be added to this cache key.\n */\nexport function configToCacheKey(config: Configuration): string {\n return [\n `experiments.timelineShowAllEvents:${config.experiments.timelineShowAllEvents}`,\n `experiments.timelineV8RuntimeCallStats:${config.experiments.timelineV8RuntimeCallStats}`,\n ].join('-');\n}\n"]}
|