Skip to content

Commit 2a31e37

Browse files
Connor ClarkDevtools-frontend LUCI CQ
authored andcommitted
[RPP] Support non-fresh traces in devtools-performance-node-link
This fixes a bug in the Viewport insight that was showing a random DOM node for a non-fresh trace. It now shows fallback text when the trace is not fresh. Fixes a similar bug that likely existed with LayoutShiftDetails, since the expected frame id is now checked before linkifying a given backend node id. Though no support for non-fresh traces was added there, as it requires more work. Bug: 371620361 Change-Id: Ia3e55b534b31d0ed9e78642c6e88b54c5b113f4d Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6152659 Auto-Submit: Connor Clark <cjamcl@chromium.org> Commit-Queue: Adriana Ixba <aixba@chromium.org> Reviewed-by: Adriana Ixba <aixba@chromium.org> Commit-Queue: Connor Clark <cjamcl@chromium.org>
1 parent 538f92a commit 2a31e37

File tree

4 files changed

+75
-40
lines changed

4 files changed

+75
-40
lines changed

front_end/panels/timeline/components/LayoutShiftDetails.ts

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -120,13 +120,20 @@ export class LayoutShiftDetails extends HTMLElement {
120120
`;
121121
}
122122

123-
#renderShiftedElements(elementsShifted: Trace.Types.Events.TraceImpactedNode[]|undefined): LitHtml.LitTemplate {
123+
#renderShiftedElements(
124+
shift: Trace.Types.Events.SyntheticLayoutShift,
125+
elementsShifted: Trace.Types.Events.TraceImpactedNode[]|undefined): LitHtml.LitTemplate {
124126
// clang-format off
125127
return html`
126128
${elementsShifted?.map(el => {
127129
if (el.node_id !== undefined) {
128130
return html`
129-
<devtools-performance-node-link .data=${{backendNodeId: el.node_id}}>
131+
<devtools-performance-node-link
132+
.data=${{
133+
backendNodeId: el.node_id,
134+
frame: shift.args.frame,
135+
// TODO(crbug.com/371620361): if ever rendered for non-fresh traces, this needs to set a fallback text value.
136+
} as Insights.NodeLink.NodeLinkData}>
130137
</devtools-performance-node-link>`;
131138
}
132139
return LitHtml.nothing;
@@ -188,26 +195,30 @@ export class LayoutShiftDetails extends HTMLElement {
188195
// clang-format on
189196
}
190197

191-
#renderUnsizedImage(node: Protocol.DOM.BackendNodeId): LitHtml.TemplateResult|null {
198+
#renderUnsizedImage(frame: string, backendNodeId: Protocol.DOM.BackendNodeId): LitHtml.TemplateResult|null {
192199
// clang-format off
193200
const el = html`
194201
<devtools-performance-node-link
195202
.data=${{
196-
backendNodeId: node,
203+
backendNodeId,
204+
frame,
205+
// TODO(crbug.com/371620361): if ever rendered for non-fresh traces, this needs to set a fallback text value. This requires
206+
// `rootCauses.unsizedImages` to have more than just the backend node id.
197207
} as Insights.NodeLink.NodeLinkData}>
198208
</devtools-performance-node-link>`;
199209
return html`
200210
<span class="culprit"><span class="culprit-type">${i18nString(UIStrings.unsizedImage)}: </span><span class="culprit-value">${el}</span></span>`;
201211
// clang-format on
202212
}
203213

204-
#renderRootCauseValues(rootCauses: Trace.Insights.Models.CLSCulprits.LayoutShiftRootCausesData|
205-
undefined): LitHtml.TemplateResult|null {
214+
#renderRootCauseValues(
215+
frame: string,
216+
rootCauses: Trace.Insights.Models.CLSCulprits.LayoutShiftRootCausesData|undefined): LitHtml.TemplateResult|null {
206217
return html`
207218
${rootCauses?.fontRequests.map(fontReq => this.#renderFontRequest(fontReq))}
208219
${rootCauses?.iframeIds.map(iframe => this.#renderIframe(iframe))}
209220
${rootCauses?.nonCompositedAnimations.map(failure => this.#renderAnimation(failure))}
210-
${rootCauses?.unsizedImages.map(image => this.#renderUnsizedImage(image))}
221+
${rootCauses?.unsizedImages.map(backendNodeId => this.#renderUnsizedImage(frame, backendNodeId))}
211222
`;
212223
}
213224

@@ -237,6 +248,8 @@ export class LayoutShiftDetails extends HTMLElement {
237248
(rootCauses.fontRequests.length || rootCauses.iframeIds.length || rootCauses.nonCompositedAnimations.length ||
238249
rootCauses.unsizedImages.length));
239250

251+
// TODO(crbug.com/371620361): Needs to show something for non-fresh recordings.
252+
240253
// clang-format off
241254
return html`
242255
<tr class="shift-row" data-ts=${shift.ts}>
@@ -245,12 +258,12 @@ export class LayoutShiftDetails extends HTMLElement {
245258
${this.#isFreshRecording ? html`
246259
<td>
247260
<div class="elements-shifted">
248-
${this.#renderShiftedElements(elementsShifted)}
261+
${this.#renderShiftedElements(shift, elementsShifted)}
249262
</div>
250263
</td>` : LitHtml.nothing}
251264
${hasCulprits && this.#isFreshRecording ? html`
252265
<td class="culprits">
253-
${this.#renderRootCauseValues(rootCauses)}
266+
${this.#renderRootCauseValues(shift.args.frame, rootCauses)}
254267
</td>` : LitHtml.nothing}
255268
</tr>`;
256269
// clang-format on

front_end/panels/timeline/components/insights/NodeLink.ts

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,57 +5,63 @@
55
// TODO: move to ui/components/node_link?
66

77
import * as Common from '../../../../core/common/common.js';
8-
import * as SDK from '../../../../core/sdk/sdk.js';
98
import type * as Protocol from '../../../../generated/protocol.js';
9+
import * as Trace from '../../../../models/trace/trace.js';
1010
import * as ComponentHelpers from '../../../../ui/components/helpers/helpers.js';
1111
import * as LitHtml from '../../../../ui/lit-html/lit-html.js';
1212

1313
const {html} = LitHtml;
1414

1515
export interface NodeLinkData {
1616
backendNodeId: Protocol.DOM.BackendNodeId;
17+
frame: string;
1718
options?: Common.Linkifier.Options;
19+
/**
20+
* Text to display if backendNodeId cannot be resolved (ie for traces loaded from disk).
21+
* Displayed as monospace code. Use this or the next field.
22+
*/
23+
fallbackHtmlSnippet?: string;
24+
/**
25+
* Text to display if backendNodeId cannot be resolved (ie for traces loaded from disk).
26+
* Displayed as plain text. Use this or the previous field.
27+
*/
28+
fallbackText?: string;
1829
}
1930

2031
export class NodeLink extends HTMLElement {
21-
2232
readonly #shadow = this.attachShadow({mode: 'open'});
2333
readonly #boundRender = this.#render.bind(this);
2434
#backendNodeId?: Protocol.DOM.BackendNodeId;
35+
#frame?: string;
2536
#options?: Common.Linkifier.Options;
37+
#fallbackHtmlSnippet?: string;
38+
#fallbackText?: string;
2639

2740
set data(data: NodeLinkData) {
2841
this.#backendNodeId = data.backendNodeId;
42+
this.#frame = data.frame;
2943
this.#options = data.options;
44+
this.#fallbackHtmlSnippet = data.fallbackHtmlSnippet;
45+
this.#fallbackText = data.fallbackText;
3046
void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#boundRender);
3147
}
3248

3349
async #linkify(): Promise<Node|undefined> {
34-
// TODO: consider using `Trace.Extras.FetchNodes.extractRelatedDOMNodesFromEvent`, which
35-
// requires parsedTrace.
36-
3750
if (this.#backendNodeId === undefined) {
3851
return;
3952
}
4053

41-
const mainTarget = SDK.TargetManager.TargetManager.instance().primaryPageTarget();
42-
if (!mainTarget) {
43-
return;
44-
}
45-
46-
const domModel = mainTarget.model(SDK.DOMModel.DOMModel);
47-
if (!domModel) {
48-
return;
49-
}
50-
51-
const backendNodeIds = new Set([this.#backendNodeId]);
52-
const domNodesMap = await domModel.pushNodesByBackendIdsToFrontend(backendNodeIds);
53-
if (!domNodesMap) {
54+
// Users of `NodeLink` do not have a parsed trace so this is a workaround. This
55+
// is an abuse of this API, but it's currently alright since the first parameter
56+
// is only used as a cache key.
57+
const domNodesMap = await Trace.Extras.FetchNodes.domNodesForMultipleBackendNodeIds(
58+
this as unknown as Trace.Handlers.Types.ParsedTrace, [this.#backendNodeId]);
59+
const node = domNodesMap.get(this.#backendNodeId);
60+
if (!node) {
5461
return;
5562
}
5663

57-
const node = domNodesMap.get(this.#backendNodeId);
58-
if (!node) {
64+
if (node.frameId() !== this.#frame) {
5965
return;
6066
}
6167

@@ -66,11 +72,20 @@ export class NodeLink extends HTMLElement {
6672

6773
async #render(): Promise<void> {
6874
const relatedNodeEl = await this.#linkify();
69-
LitHtml.render(
70-
html`<div class='node-link'>
71-
${relatedNodeEl}
72-
</div>`,
73-
this.#shadow, {host: this});
75+
76+
let template;
77+
if (relatedNodeEl) {
78+
template = html`<div class='node-link'>${relatedNodeEl}</div>`;
79+
} else if (this.#fallbackHtmlSnippet) {
80+
// TODO: Use CodeHighlighter.
81+
template = html`<pre style='text-wrap: auto'>${this.#fallbackHtmlSnippet}</pre>`;
82+
} else if (this.#fallbackText) {
83+
template = html`<span>${this.#fallbackText}</span>`;
84+
} else {
85+
template = LitHtml.nothing;
86+
}
87+
88+
LitHtml.render(template, this.#shadow, {host: this});
7489
}
7590
}
7691

front_end/panels/timeline/components/insights/Viewport.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,27 @@ export class Viewport extends BaseInsightComponent<ViewportInsightModel> {
2626
return this.model?.metricSavings?.INP ?? null;
2727
}
2828

29-
override renderContent(): LitHtml.LitTemplate {
30-
if (!this.model) {
29+
renderContent(): LitHtml.LitTemplate {
30+
if (!this.model || !this.model.viewportEvent) {
3131
return LitHtml.nothing;
3232
}
3333

34-
const backendNodeId = this.model.viewportEvent?.args.data.node_id;
34+
const backendNodeId = this.model.viewportEvent.args.data.node_id;
35+
if (backendNodeId === undefined) {
36+
return LitHtml.nothing;
37+
}
3538

3639
// clang-format off
3740
return html`
3841
<div>
39-
${backendNodeId !== undefined ? html`<devtools-performance-node-link
42+
<devtools-performance-node-link
4043
.data=${{
4144
backendNodeId,
42-
options: {tooltip: this.model.viewportEvent?.args.data.content},
45+
frame: this.model.viewportEvent.args.data.frame ?? '',
46+
options: {tooltip: this.model.viewportEvent.args.data.content},
47+
fallbackHtmlSnippet: `<meta name=viewport content="${this.model.viewportEvent.args.data.content}">`,
4348
}}>
44-
</devtools-performance-node-link>` : LitHtml.nothing}
49+
</devtools-performance-node-link>
4550
</div>`;
4651
// clang-format on
4752
}

front_end/ui/visual_logging/KnownContextValues.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3466,6 +3466,7 @@ export const knownContextValues = new Set([
34663466
'timeline.insights-tab',
34673467
'timeline.insights.cls-culprits',
34683468
'timeline.insights.document-latency',
3469+
'timeline.insights.dom-size',
34693470
'timeline.insights.font-display',
34703471
'timeline.insights.image-delivery',
34713472
'timeline.insights.inp',
@@ -3532,6 +3533,7 @@ export const knownContextValues = new Set([
35323533
'timeline.timings',
35333534
'timeline.toggle-insight.cls-culprits',
35343535
'timeline.toggle-insight.document-latency',
3536+
'timeline.toggle-insight.dom-size',
35353537
'timeline.toggle-insight.font-display',
35363538
'timeline.toggle-insight.image-delivery',
35373539
'timeline.toggle-insight.inp',

0 commit comments

Comments
 (0)