chrome-devtools-frontend 1.0.1519267 → 1.0.1520535
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/config/owner/COMMON_OWNERS +1 -2
- package/config/typescript/tsconfig.eslint.json +12 -1
- package/docs/ui_engineering.md +1011 -0
- package/front_end/core/host/GdpClient.ts +26 -5
- package/front_end/core/sdk/NetworkManager.ts +1 -0
- package/front_end/core/sdk/NetworkRequest.ts +10 -0
- package/front_end/entrypoints/main/MainImpl.ts +6 -1
- package/front_end/entrypoints/main/main-meta.ts +3 -3
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +50 -48
- package/front_end/models/ai_assistance/agents/PerformanceAnnotationsAgent.ts +4 -4
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +128 -30
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +98 -63
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +317 -640
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +36 -21
- package/front_end/models/ai_assistance/performance/AICallTree.snapshot.txt +75 -0
- package/front_end/models/ai_assistance/performance/AICallTree.ts +14 -6
- package/front_end/models/ai_assistance/performance/AIContext.ts +62 -7
- package/front_end/models/ai_code_completion/AiCodeCompletion.ts +5 -5
- package/front_end/models/badges/Badge.ts +6 -1
- package/front_end/models/badges/StarterBadge.ts +5 -0
- package/front_end/models/badges/UserBadges.ts +5 -4
- package/front_end/models/javascript_metadata/NativeFunctions.js +5 -1
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +14 -7
- package/front_end/panels/ai_assistance/PatchWidget.ts +17 -55
- package/front_end/panels/ai_assistance/components/ChatView.ts +45 -69
- package/front_end/panels/ai_assistance/components/PerformanceAgentMarkdownRenderer.ts +47 -1
- package/front_end/panels/ai_assistance/components/chatView.css +13 -1
- package/front_end/panels/animation/AnimationTimeline.ts +1 -1
- package/front_end/panels/animation/animationTimeline.css +4 -0
- package/front_end/panels/application/preloading/components/PreloadingString.ts +2 -5
- package/front_end/panels/common/AiCodeCompletionTeaser.ts +5 -0
- package/front_end/panels/common/aiCodeCompletionTeaser.css +6 -1
- package/front_end/panels/console/ConsolePrompt.ts +6 -0
- package/front_end/panels/console/ConsoleView.ts +4 -2
- package/front_end/panels/coverage/CoverageListView.ts +146 -198
- package/front_end/panels/coverage/CoverageView.ts +48 -18
- package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +2 -0
- package/front_end/panels/network/NetworkDataGridNode.ts +22 -0
- package/front_end/panels/network/NetworkLogViewColumns.ts +9 -0
- package/front_end/panels/recorder/components/CreateRecordingView.ts +2 -0
- package/front_end/panels/search/SearchResultsPane.ts +48 -15
- package/front_end/panels/search/SearchView.ts +33 -30
- package/front_end/panels/search/searchView.css +0 -2
- package/front_end/panels/settings/components/SyncSection.ts +4 -4
- package/front_end/panels/sources/AiCodeCompletionPlugin.ts +1 -4
- package/front_end/panels/sources/DebuggerPlugin.ts +4 -0
- package/front_end/panels/timeline/ThirdPartyTreeView.ts +1 -1
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +0 -8
- package/front_end/panels/timeline/TimelineFlameChartView.ts +5 -5
- package/front_end/panels/timeline/TimelinePanel.ts +2 -0
- package/front_end/panels/timeline/TimelineTreeView.ts +1 -1
- package/front_end/panels/timeline/components/ExportTraceOptions.ts +56 -4
- package/front_end/panels/timeline/components/exportTraceOptions.css +5 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/lighthouse/README.chromium +8 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/Realm.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.js +15 -16
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/PipeTransport.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Function.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +4 -4
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserLauncher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.js +15 -16
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/PipeTransport.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/Function.js.map +1 -1
- package/front_end/third_party/puppeteer/package/package.json +3 -2
- package/front_end/third_party/puppeteer/package/src/generated/version.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/node/BrowserLauncher.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/node/PipeTransport.ts +15 -17
- package/front_end/third_party/puppeteer/package/src/revisions.ts +2 -2
- package/front_end/third_party/puppeteer/package/src/util/Function.ts +1 -1
- package/front_end/tsconfig.json +12 -1
- package/front_end/ui/legacy/InspectorView.ts +86 -13
- package/front_end/ui/legacy/TabbedPane.ts +2 -1
- package/front_end/ui/visual_logging/KnownContextValues.ts +6 -0
- package/front_end/ui/visual_logging/LoggingEvents.ts +1 -1
- package/package.json +1 -1
package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt
CHANGED
@@ -7,7 +7,7 @@ This insight is used to analyze the time spent that contributed to the final LCP
|
|
7
7
|
|
8
8
|
## Detailed analysis:
|
9
9
|
The Largest Contentful Paint (LCP) time for this navigation was 240 ms.
|
10
|
-
The LCP element (IMG) is an image fetched from
|
10
|
+
The LCP element (IMG, nodeId: 23) is an image fetched from https://creativetouchrotherham.co.uk/images/creative-touch-home/creative_touch_rotherham_homehero/creative_touch_rotherham_homehero_700.webp (eventKey: s-1418, ts: 397824185142).
|
11
11
|
## LCP resource network request: https://creativetouchrotherham.co.uk/images/creative-touch-home/creative_touch_rotherham_homehero/creative_touch_rotherham_homehero_700.webp
|
12
12
|
eventKey: s-1418
|
13
13
|
Timings:
|
@@ -68,7 +68,7 @@ This insight is used to analyze the time spent that contributed to the final LCP
|
|
68
68
|
|
69
69
|
## Detailed analysis:
|
70
70
|
The Largest Contentful Paint (LCP) time for this navigation was 129 ms.
|
71
|
-
The LCP element is an image fetched from
|
71
|
+
The LCP element is an image fetched from https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/4i7JstVZvgTFk9dxCe4a.svg (eventKey: s-1314, ts: 122411037986).
|
72
72
|
## LCP resource network request: https://web-dev.imgix.net/image/kheDArv5csY6rvQUJDbWRscckLr1/4i7JstVZvgTFk9dxCe4a.svg
|
73
73
|
eventKey: s-1314
|
74
74
|
Timings:
|
@@ -186,7 +186,7 @@ It is important that all of these checks pass to minimize the delay between the
|
|
186
186
|
|
187
187
|
## Detailed analysis:
|
188
188
|
The Largest Contentful Paint (LCP) time for this navigation was 1,077 ms.
|
189
|
-
The LCP element is an image fetched from
|
189
|
+
The LCP element is an image fetched from http://localhost:8787/lcp-discovery-delay/lcp-image.jpg (eventKey: s-25281, ts: 197696859337).
|
190
190
|
## LCP resource network request: http://localhost:8787/lcp-discovery-delay/lcp-image.jpg
|
191
191
|
eventKey: s-25281
|
192
192
|
Timings:
|
@@ -310,7 +310,7 @@ Layout shifts in this cluster:
|
|
310
310
|
- Start time: 472 ms
|
311
311
|
- Score: 0.0003
|
312
312
|
- Potential root causes:
|
313
|
-
- A font that was loaded over the network
|
313
|
+
- A font that was loaded over the network: https://fonts.gstatic.com/s/specialgothicexpandedone/v2/IurO6Zxk74-YaYk1r3HOet4g75ENmBxUmOK61tA0Iu5QmJF_.woff2 (eventKey: s-1158, ts: 1355335690947).
|
314
314
|
### Layout shift 2:
|
315
315
|
- Start time: 857 ms
|
316
316
|
- Score: 0.0844
|
@@ -320,12 +320,12 @@ Layout shifts in this cluster:
|
|
320
320
|
- Start time: 1,352 ms
|
321
321
|
- Score: 0.0068
|
322
322
|
- Potential root causes:
|
323
|
-
- An unsized image (IMG) (url: http://localhost:8000/unsized-image.png).
|
323
|
+
- An unsized image (IMG) (url: http://localhost:8000/unsized-image.png (eventKey: s-4487, ts: 1355336697136)).
|
324
324
|
### Layout shift 4:
|
325
325
|
- Start time: 1,537 ms
|
326
326
|
- Score: 0.3344
|
327
327
|
- Potential root causes:
|
328
|
-
- An unsized image (IMG) (url: http://localhost:8000/unsized-image.png).
|
328
|
+
- An unsized image (IMG) (url: http://localhost:8000/unsized-image.png (eventKey: s-4487, ts: 1355336697136)).
|
329
329
|
### Layout shift 5:
|
330
330
|
- Start time: 2,343 ms
|
331
331
|
- Score: 0.3396
|
@@ -334,7 +334,105 @@ Layout shifts in this cluster:
|
|
334
334
|
## Estimated savings: none
|
335
335
|
|
336
336
|
## External resources:
|
337
|
-
- https://
|
337
|
+
- https://web.dev/articles/cls
|
338
|
+
- https://web.dev/articles/optimize-cls
|
339
|
+
=== end content
|
340
|
+
|
341
|
+
Title: PerformanceInsightFormatter CLS serializes correctly when there are no layout shifts
|
342
|
+
Content:
|
343
|
+
## Insight Title: Layout shift culprits
|
344
|
+
|
345
|
+
## Insight Summary:
|
346
|
+
Cumulative Layout Shifts (CLS) is a measure of the largest burst of layout shifts for every unexpected layout shift that occurs during the lifecycle of a page. This is a Core Web Vital and the thresholds for categorizing a score are:
|
347
|
+
- Good: 0.1 or less
|
348
|
+
- Needs improvement: more than 0.1 and less than or equal to 0.25
|
349
|
+
- Bad: over 0.25
|
350
|
+
|
351
|
+
## Detailed analysis:
|
352
|
+
No layout shifts were found.
|
353
|
+
|
354
|
+
## Estimated savings: none
|
355
|
+
|
356
|
+
## External resources:
|
357
|
+
- https://web.dev/articles/cls
|
358
|
+
- https://web.dev/articles/optimize-cls
|
359
|
+
=== end content
|
360
|
+
|
361
|
+
Title: PerformanceInsightFormatter CLS outputs information on non-composited animations
|
362
|
+
Content:
|
363
|
+
## Insight Title: Layout shift culprits
|
364
|
+
|
365
|
+
## Insight Summary:
|
366
|
+
Cumulative Layout Shifts (CLS) is a measure of the largest burst of layout shifts for every unexpected layout shift that occurs during the lifecycle of a page. This is a Core Web Vital and the thresholds for categorizing a score are:
|
367
|
+
- Good: 0.1 or less
|
368
|
+
- Needs improvement: more than 0.1 and less than or equal to 0.25
|
369
|
+
- Bad: over 0.25
|
370
|
+
|
371
|
+
## Detailed analysis:
|
372
|
+
The worst layout shift cluster was the cluster that started at 60 ms and ended at 1,243 ms, with a duration of 1,183 ms.
|
373
|
+
The score for this cluster is 0.0140.
|
374
|
+
|
375
|
+
Layout shifts in this cluster:
|
376
|
+
### Layout shift 1:
|
377
|
+
- Start time: 60 ms
|
378
|
+
- Score: 0.0012
|
379
|
+
- No potential root causes identified
|
380
|
+
### Layout shift 2:
|
381
|
+
- Start time: 76 ms
|
382
|
+
- Score: 0.0012
|
383
|
+
- No potential root causes identified
|
384
|
+
### Layout shift 3:
|
385
|
+
- Start time: 93 ms
|
386
|
+
- Score: 0.0012
|
387
|
+
- No potential root causes identified
|
388
|
+
### Layout shift 4:
|
389
|
+
- Start time: 110 ms
|
390
|
+
- Score: 0.0012
|
391
|
+
- No potential root causes identified
|
392
|
+
### Layout shift 5:
|
393
|
+
- Start time: 126 ms
|
394
|
+
- Score: 0.0012
|
395
|
+
- No potential root causes identified
|
396
|
+
### Layout shift 6:
|
397
|
+
- Start time: 143 ms
|
398
|
+
- Score: 0.0012
|
399
|
+
- No potential root causes identified
|
400
|
+
### Layout shift 7:
|
401
|
+
- Start time: 160 ms
|
402
|
+
- Score: 0.0012
|
403
|
+
- No potential root causes identified
|
404
|
+
### Layout shift 8:
|
405
|
+
- Start time: 176 ms
|
406
|
+
- Score: 0.0012
|
407
|
+
- No potential root causes identified
|
408
|
+
### Layout shift 9:
|
409
|
+
- Start time: 193 ms
|
410
|
+
- Score: 0.0012
|
411
|
+
- No potential root causes identified
|
412
|
+
### Layout shift 10:
|
413
|
+
- Start time: 210 ms
|
414
|
+
- Score: 0.0012
|
415
|
+
- No potential root causes identified
|
416
|
+
### Layout shift 11:
|
417
|
+
- Start time: 226 ms
|
418
|
+
- Score: 0.0012
|
419
|
+
- No potential root causes identified
|
420
|
+
### Layout shift 12:
|
421
|
+
- Start time: 243 ms
|
422
|
+
- Score: 0.0012
|
423
|
+
- Potential root causes:
|
424
|
+
- A non-composited animation:
|
425
|
+
- non-composited animation: `change-height`
|
426
|
+
Animation name: change-height
|
427
|
+
Unsupported CSS properties:
|
428
|
+
- height
|
429
|
+
Failure reasons:
|
430
|
+
- TARGET_HAS_INVALID_COMPOSITING_STATE, UNSUPPORTED_CSS_PROPERTY
|
431
|
+
|
432
|
+
## Estimated savings: none
|
433
|
+
|
434
|
+
## External resources:
|
435
|
+
- https://web.dev/articles/cls
|
338
436
|
- https://web.dev/articles/optimize-cls
|
339
437
|
=== end content
|
340
438
|
|
@@ -589,16 +687,16 @@ Total legacy JavaScript: 8 files.
|
|
589
687
|
|
590
688
|
Legacy JavaScript by file:
|
591
689
|
|
592
|
-
- Script: https://s.yimg.com/aaq/benji/benji-2.2.99.js - Wasted bytes: 37204 bytes
|
690
|
+
- Script: https://s.yimg.com/aaq/benji/benji-2.2.99.js (eventKey: s-3387, ts: 157423742567) - Wasted bytes: 37204 bytes
|
593
691
|
Matches:
|
594
692
|
Line: 0, Column: 133, Name: Promise.allSettled
|
595
693
|
|
596
|
-
- Script: https://s.yimg.com/aaq/c/25fa214.caas-news_web.min.js - Wasted bytes: 36084 bytes
|
694
|
+
- Script: https://s.yimg.com/aaq/c/25fa214.caas-news_web.min.js (eventKey: s-3412, ts: 157423743431) - Wasted bytes: 36084 bytes
|
597
695
|
Matches:
|
598
696
|
Line: 0, Column: 13310, Name: Array.from
|
599
697
|
Line: 0, Column: 14623, Name: Object.assign
|
600
698
|
|
601
|
-
- Script: https://s.yimg.com/du/ay/wnsrvbjmeprtfrnfx.js - Wasted bytes: 12850 bytes
|
699
|
+
- Script: https://s.yimg.com/du/ay/wnsrvbjmeprtfrnfx.js (eventKey: s-6273, ts: 157423760794) - Wasted bytes: 12850 bytes
|
602
700
|
Matches:
|
603
701
|
Line: 111, Column: 7829, Name: @babel/plugin-transform-spread
|
604
702
|
Line: 111, Column: 1794, Name: Array.prototype.find
|
@@ -607,21 +705,21 @@ Line: 111, Column: 2748, Name: Object.values
|
|
607
705
|
Line: 111, Column: 2473, Name: String.prototype.includes
|
608
706
|
Line: 111, Column: 2627, Name: String.prototype.startsWith
|
609
707
|
|
610
|
-
- Script: https://static.criteo.net/js/ld/publishertag.prebid.144.js - Wasted bytes: 10751 bytes
|
708
|
+
- Script: https://static.criteo.net/js/ld/publishertag.prebid.144.js (eventKey: s-257378, ts: 157426026656) - Wasted bytes: 10751 bytes
|
611
709
|
Matches:
|
612
710
|
Line: 1, Column: 74871, Name: Array.isArray
|
613
711
|
Line: 1, Column: 75344, Name: Array.prototype.filter
|
614
712
|
Line: 1, Column: 75013, Name: Array.prototype.indexOf
|
615
713
|
|
616
|
-
- Script: https://s.yimg.com/oa/consent.js - Wasted bytes: 8157 bytes
|
714
|
+
- Script: https://s.yimg.com/oa/consent.js (eventKey: s-3384, ts: 157423742450) - Wasted bytes: 8157 bytes
|
617
715
|
Matches:
|
618
716
|
Line: 1, Column: 132267, Name: Array.prototype.includes
|
619
717
|
|
620
|
-
- Script: https://pm-widget.taboola.com/yahooweb-network/pmk-20220605.1.js - Wasted bytes: 7625 bytes
|
718
|
+
- Script: https://pm-widget.taboola.com/yahooweb-network/pmk-20220605.1.js (eventKey: s-52229, ts: 157424128231) - Wasted bytes: 7625 bytes
|
621
719
|
Matches:
|
622
720
|
Line: 181, Column: 26, Name: Object.keys
|
623
721
|
|
624
|
-
- Script: https://news.yahoo.com/ - Wasted bytes: 7141 bytes
|
722
|
+
- Script: https://news.yahoo.com/ (eventKey: s-2116, ts: 157423489126) - Wasted bytes: 7141 bytes
|
625
723
|
Matches:
|
626
724
|
Line: 0, Column: 8382, Name: @babel/plugin-transform-classes
|
627
725
|
Line: 0, Column: 107712, Name: Array.prototype.filter
|
@@ -629,7 +727,7 @@ Line: 0, Column: 107393, Name: Array.prototype.forEach
|
|
629
727
|
Line: 0, Column: 108005, Name: Array.prototype.map
|
630
728
|
Line: 0, Column: 108358, Name: String.prototype.includes
|
631
729
|
|
632
|
-
- Script: https://cdn.taboola.com/libtrc/yahooweb-network/loader.js - Wasted bytes: 7061 bytes
|
730
|
+
- Script: https://cdn.taboola.com/libtrc/yahooweb-network/loader.js (eventKey: s-6352, ts: 157423761978) - Wasted bytes: 7061 bytes
|
633
731
|
Matches:
|
634
732
|
Line: 0, Column: 390544, Name: Object.entries
|
635
733
|
Line: 0, Column: 390688, Name: Object.values
|
@@ -669,12 +767,12 @@ This insight identifies font issues when a webpage uses custom fonts, for exampl
|
|
669
767
|
## Detailed analysis:
|
670
768
|
The following font display issues were found:
|
671
769
|
|
672
|
-
- Font name: jizaRExUiTo99u79D0KExcOPIDU.woff2, URL: https://fonts.gstatic.com/s/ptsans/v17/jizaRExUiTo99u79D0KExcOPIDU.woff2, Property 'font-display' set to: 'auto', Wasted time: 20 ms.
|
673
|
-
- Font name: SlGVmQWMvZQIdix7AFxXkHNSbRYXags.woff2, URL: https://fonts.gstatic.com/s/droidsans/v18/SlGVmQWMvZQIdix7AFxXkHNSbRYXags.woff2, Property 'font-display' set to: 'auto', Wasted time: 15 ms.
|
674
|
-
- Font name: jizfRExUiTo99u79B_mh0O6tLR8a8zI.woff2, URL: https://fonts.gstatic.com/s/ptsans/v17/jizfRExUiTo99u79B_mh0O6tLR8a8zI.woff2, Property 'font-display' set to: 'auto', Wasted time: 15 ms.
|
675
|
-
- Font name: SlGWmQWMvZQIdix7AFxXmMh3eDs1ZyHKpWg.woff2, URL: https://fonts.gstatic.com/s/droidsans/v18/SlGWmQWMvZQIdix7AFxXmMh3eDs1ZyHKpWg.woff2, Property 'font-display' set to: 'auto', Wasted time: 15 ms.
|
676
|
-
- Font name: EJRVQgYoZZY2vCFuvAFWzr-_dSb_.woff2, URL: https://fonts.gstatic.com/s/ptserif/v18/EJRVQgYoZZY2vCFuvAFWzr-_dSb_.woff2, Property 'font-display' set to: 'auto', Wasted time: 15 ms.
|
677
|
-
- Font name: S6u9w4BMUTPHh6UVSwiPGQ3q5d0.woff2, URL: https://fonts.gstatic.com/s/lato/v24/S6u9w4BMUTPHh6UVSwiPGQ3q5d0.woff2, Property 'font-display' set to: 'auto', Wasted time: 10 ms.
|
770
|
+
- Font name: jizaRExUiTo99u79D0KExcOPIDU.woff2, URL: https://fonts.gstatic.com/s/ptsans/v17/jizaRExUiTo99u79D0KExcOPIDU.woff2 (eventKey: s-5246, ts: 409057956748), Property 'font-display' set to: 'auto', Wasted time: 20 ms.
|
771
|
+
- Font name: SlGVmQWMvZQIdix7AFxXkHNSbRYXags.woff2, URL: https://fonts.gstatic.com/s/droidsans/v18/SlGVmQWMvZQIdix7AFxXkHNSbRYXags.woff2 (eventKey: s-5232, ts: 409057956250), Property 'font-display' set to: 'auto', Wasted time: 15 ms.
|
772
|
+
- Font name: jizfRExUiTo99u79B_mh0O6tLR8a8zI.woff2, URL: https://fonts.gstatic.com/s/ptsans/v17/jizfRExUiTo99u79B_mh0O6tLR8a8zI.woff2 (eventKey: s-5259, ts: 409057957711), Property 'font-display' set to: 'auto', Wasted time: 15 ms.
|
773
|
+
- Font name: SlGWmQWMvZQIdix7AFxXmMh3eDs1ZyHKpWg.woff2, URL: https://fonts.gstatic.com/s/droidsans/v18/SlGWmQWMvZQIdix7AFxXmMh3eDs1ZyHKpWg.woff2 (eventKey: s-5269, ts: 409057958585), Property 'font-display' set to: 'auto', Wasted time: 15 ms.
|
774
|
+
- Font name: EJRVQgYoZZY2vCFuvAFWzr-_dSb_.woff2, URL: https://fonts.gstatic.com/s/ptserif/v18/EJRVQgYoZZY2vCFuvAFWzr-_dSb_.woff2 (eventKey: s-5325, ts: 409057959655), Property 'font-display' set to: 'auto', Wasted time: 15 ms.
|
775
|
+
- Font name: S6u9w4BMUTPHh6UVSwiPGQ3q5d0.woff2, URL: https://fonts.gstatic.com/s/lato/v24/S6u9w4BMUTPHh6UVSwiPGQ3q5d0.woff2 (eventKey: s-5238, ts: 409057956530), Property 'font-display' set to: 'auto', Wasted time: 10 ms.
|
678
776
|
|
679
777
|
Consider setting [`font-display`](https://developer.chrome.com/blog/font-display) to `swap` or `optional` to ensure text is consistently visible. `swap` can be further optimized to mitigate layout shifts with [font metric overrides](https://developer.chrome.com/blog/font-fallbacks).
|
680
778
|
|
@@ -714,28 +812,28 @@ Total potential savings: 2 MB
|
|
714
812
|
|
715
813
|
The following images could be optimized:
|
716
814
|
|
717
|
-
### https://images.ctfassets.net/u275ja1nivmq/6T6z40ay5GFCUtwV7DONgh/0e23606ed1692d9721ab0f39a8d8a99e/yeti_cover.jpg
|
815
|
+
### https://images.ctfassets.net/u275ja1nivmq/6T6z40ay5GFCUtwV7DONgh/0e23606ed1692d9721ab0f39a8d8a99e/yeti_cover.jpg (eventKey: s-1212, ts: 59728701403)
|
718
816
|
- Potential savings: 1.1 MB
|
719
817
|
- Optimizations:
|
720
818
|
Using a modern image format (WebP, AVIF) or increasing the image compression could improve this image's download size. (Est 1.1 MB)
|
721
819
|
|
722
|
-
### https://raw.githubusercontent.com/GoogleChrome/lighthouse/refs/heads/main/cli/test/fixtures/dobetterweb/lighthouse-rotating.gif
|
820
|
+
### https://raw.githubusercontent.com/GoogleChrome/lighthouse/refs/heads/main/cli/test/fixtures/dobetterweb/lighthouse-rotating.gif (eventKey: s-1216, ts: 59728702014)
|
723
821
|
- Potential savings: 682 kB
|
724
822
|
- Optimizations:
|
725
823
|
Using video formats instead of GIFs can improve the download size of animated content. (Est 682 kB)
|
726
824
|
|
727
|
-
### https://onlinepngtools.com/images/examples-onlinepngtools/elephant-hd-quality.png
|
825
|
+
### https://onlinepngtools.com/images/examples-onlinepngtools/elephant-hd-quality.png (eventKey: s-1228, ts: 59728702737)
|
728
826
|
- Potential savings: 176 kB
|
729
827
|
- Optimizations:
|
730
828
|
Using a modern image format (WebP, AVIF) or increasing the image compression could improve this image's download size. (Est 134.1 kB)
|
731
829
|
This image file is larger than it needs to be (640x436) for its displayed dimensions (200x136). Use responsive images to reduce the image download size. (Est 162.9 kB)
|
732
830
|
|
733
|
-
### https://images.ctfassets.net/u275ja1nivmq/6T6z40ay5GFCUtwV7DONgh/0e23606ed1692d9721ab0f39a8d8a99e/yeti_cover.jpg?fm=webp
|
831
|
+
### https://images.ctfassets.net/u275ja1nivmq/6T6z40ay5GFCUtwV7DONgh/0e23606ed1692d9721ab0f39a8d8a99e/yeti_cover.jpg?fm=webp (eventKey: s-1224, ts: 59728702313)
|
734
832
|
- Potential savings: 49.8 kB
|
735
833
|
- Optimizations:
|
736
834
|
Increasing the image compression factor could improve this image's download size. (Est 49.8 kB)
|
737
835
|
|
738
|
-
### https://raw.githubusercontent.com/GoogleChrome/lighthouse/refs/heads/main/cli/test/fixtures/byte-efficiency/lighthouse-2048x1356.webp
|
836
|
+
### https://raw.githubusercontent.com/GoogleChrome/lighthouse/refs/heads/main/cli/test/fixtures/byte-efficiency/lighthouse-2048x1356.webp (eventKey: s-1226, ts: 59728702539)
|
739
837
|
- Potential savings: 41.4 kB
|
740
838
|
- Optimizations:
|
741
839
|
This image file is larger than it needs to be (2048x1356) for its displayed dimensions (200x132). Use responsive images to reduce the image download size. (Est 41.4 kB)
|
@@ -852,9 +950,9 @@ The network dependency tree checks found one or more problems.
|
|
852
950
|
Max critical path latency is 5,015 ms
|
853
951
|
|
854
952
|
The following is the critical request chain:
|
855
|
-
- http://localhost:8787/lcp-iframes/index.html (5,006 ms) (longest chain)
|
856
|
-
- http://localhost:8787/lcp-iframes/app.js (5,015 ms) (longest chain)
|
857
|
-
- http://localhost:8787/lcp-iframes/app.css (5,010 ms)
|
953
|
+
- http://localhost:8787/lcp-iframes/index.html (eventKey: s-7103, ts: 566777570990) (5,006 ms) (longest chain)
|
954
|
+
- http://localhost:8787/lcp-iframes/app.js (eventKey: s-7225, ts: 566782574106) (5,015 ms) (longest chain)
|
955
|
+
- http://localhost:8787/lcp-iframes/app.css (eventKey: s-7213, ts: 566782573909) (5,010 ms)
|
858
956
|
|
859
957
|
no origins were preconnected.
|
860
958
|
|
@@ -979,7 +1077,7 @@ This insight identifies static resources that are not cached effectively by the
|
|
979
1077
|
## Detailed analysis:
|
980
1078
|
The following resources were associated with ineffficient cache policies:
|
981
1079
|
|
982
|
-
- https://chromedevtools.github.io/performance-stories/lcp-large-image/app.css
|
1080
|
+
- https://chromedevtools.github.io/performance-stories/lcp-large-image/app.css (eventKey: s-1106, ts: 658799777502)
|
983
1081
|
- Cache Time to Live (TTL): 600 seconds
|
984
1082
|
- Wasted bytes: 0 B
|
985
1083
|
|
@@ -39,14 +39,15 @@ function getLCPData(parsedTrace: Trace.TraceModel.ParsedTrace, frameId: string,
|
|
39
39
|
};
|
40
40
|
}
|
41
41
|
|
42
|
-
export class PerformanceInsightFormatter
|
42
|
+
export class PerformanceInsightFormatter {
|
43
|
+
#traceFormatter: PerformanceTraceFormatter;
|
43
44
|
#insight: Trace.Insights.Types.InsightModel;
|
44
45
|
#parsedTrace: Trace.TraceModel.ParsedTrace;
|
45
46
|
|
46
47
|
constructor(focus: AgentFocus, insight: Trace.Insights.Types.InsightModel) {
|
47
|
-
|
48
|
+
this.#traceFormatter = new PerformanceTraceFormatter(focus);
|
48
49
|
this.#insight = insight;
|
49
|
-
this.#parsedTrace = focus.
|
50
|
+
this.#parsedTrace = focus.parsedTrace;
|
50
51
|
}
|
51
52
|
|
52
53
|
#formatMilli(x?: number): string {
|
@@ -63,6 +64,27 @@ export class PerformanceInsightFormatter extends PerformanceTraceFormatter {
|
|
63
64
|
return this.#formatMilli(Trace.Helpers.Timing.microToMilli(x as Trace.Types.Timing.Micro));
|
64
65
|
}
|
65
66
|
|
67
|
+
#formatRequestUrl(request: Trace.Types.Events.SyntheticNetworkRequest): string {
|
68
|
+
return `${request.args.data.url} ${this.#traceFormatter.serializeEvent(request)}`;
|
69
|
+
}
|
70
|
+
|
71
|
+
#formatScriptUrl(script: Trace.Handlers.ModelHandlers.Scripts.Script): string {
|
72
|
+
if (script.request) {
|
73
|
+
return this.#formatRequestUrl(script.request);
|
74
|
+
}
|
75
|
+
|
76
|
+
return script.url ?? script.sourceUrl ?? script.scriptId;
|
77
|
+
}
|
78
|
+
|
79
|
+
#formatUrl(url: string): string {
|
80
|
+
const request = this.#parsedTrace.data.NetworkRequests.byTime.find(request => request.args.data.url === url);
|
81
|
+
if (request) {
|
82
|
+
return this.#formatRequestUrl(request);
|
83
|
+
}
|
84
|
+
|
85
|
+
return url;
|
86
|
+
}
|
87
|
+
|
66
88
|
/**
|
67
89
|
* Information about LCP which we pass to the LLM for all insights that relate to LCP.
|
68
90
|
*/
|
@@ -81,16 +103,17 @@ export class PerformanceInsightFormatter extends PerformanceTraceFormatter {
|
|
81
103
|
}
|
82
104
|
|
83
105
|
const {metricScore, lcpRequest, lcpEvent} = data;
|
84
|
-
const theLcpElement =
|
85
|
-
|
106
|
+
const theLcpElement = lcpEvent.args.data?.nodeName ?
|
107
|
+
`The LCP element (${lcpEvent.args.data.nodeName}, nodeId: ${lcpEvent.args.data.nodeId})` :
|
108
|
+
'The LCP element';
|
86
109
|
const parts: string[] = [
|
87
110
|
`The Largest Contentful Paint (LCP) time for this navigation was ${this.#formatMicro(metricScore.timing)}.`,
|
88
111
|
];
|
89
112
|
|
90
113
|
if (lcpRequest) {
|
91
|
-
parts.push(`${theLcpElement} is an image fetched from
|
92
|
-
const request =
|
93
|
-
|
114
|
+
parts.push(`${theLcpElement} is an image fetched from ${this.#formatRequestUrl(lcpRequest)}.`);
|
115
|
+
const request = this.#traceFormatter.formatNetworkRequests(
|
116
|
+
[lcpRequest], {verbose: true, customTitle: 'LCP resource network request'});
|
94
117
|
parts.push(request);
|
95
118
|
} else {
|
96
119
|
parts.push(`${theLcpElement} is text and was not fetched from the network.`);
|
@@ -203,7 +226,7 @@ export class PerformanceInsightFormatter extends PerformanceTraceFormatter {
|
|
203
226
|
let output = 'The following resources were associated with ineffficient cache policies:\n';
|
204
227
|
|
205
228
|
for (const entry of insight.requests) {
|
206
|
-
output += `\n- ${entry.request
|
229
|
+
output += `\n- ${this.#formatRequestUrl(entry.request)}`;
|
207
230
|
output += `\n - Cache Time to Live (TTL): ${entry.ttl} seconds`;
|
208
231
|
output += `\n - Wasted bytes: ${bytes(entry.wastedBytes)}`;
|
209
232
|
}
|
@@ -212,6 +235,57 @@ export class PerformanceInsightFormatter extends PerformanceTraceFormatter {
|
|
212
235
|
return output;
|
213
236
|
}
|
214
237
|
|
238
|
+
#formatLayoutShift(
|
239
|
+
shift: Trace.Types.Events.SyntheticLayoutShift, index: number,
|
240
|
+
rootCauses?: Trace.Insights.Models.CLSCulprits.LayoutShiftRootCausesData): string {
|
241
|
+
const baseTime = this.#parsedTrace.data.Meta.traceBounds.min;
|
242
|
+
|
243
|
+
const potentialRootCauses: string[] = [];
|
244
|
+
if (rootCauses) {
|
245
|
+
rootCauses.iframes.forEach(
|
246
|
+
iframe => potentialRootCauses.push(
|
247
|
+
`- An iframe (id: ${iframe.frame}, url: ${iframe.url ?? 'unknown'} was injected into the page)`));
|
248
|
+
rootCauses.webFonts.forEach(req => {
|
249
|
+
potentialRootCauses.push(`- A font that was loaded over the network: ${this.#formatRequestUrl(req)}.`);
|
250
|
+
});
|
251
|
+
rootCauses.nonCompositedAnimations.forEach(nonCompositedFailure => {
|
252
|
+
potentialRootCauses.push('- A non-composited animation:');
|
253
|
+
|
254
|
+
const animationInfoOutput = [];
|
255
|
+
potentialRootCauses.push(`- non-composited animation: \`${nonCompositedFailure.name || '(unnamed)'}\``);
|
256
|
+
if (nonCompositedFailure.name) {
|
257
|
+
animationInfoOutput.push(`Animation name: ${nonCompositedFailure.name}`);
|
258
|
+
}
|
259
|
+
if (nonCompositedFailure.unsupportedProperties) {
|
260
|
+
animationInfoOutput.push('Unsupported CSS properties:');
|
261
|
+
animationInfoOutput.push('- ' + nonCompositedFailure.unsupportedProperties.join(', '));
|
262
|
+
}
|
263
|
+
animationInfoOutput.push('Failure reasons:');
|
264
|
+
animationInfoOutput.push(' - ' + nonCompositedFailure.failureReasons.join(', '));
|
265
|
+
|
266
|
+
// Extra padding to the detail to not mess up the indentation.
|
267
|
+
potentialRootCauses.push(animationInfoOutput.map(l => ' '.repeat(4) + l).join('\n'));
|
268
|
+
});
|
269
|
+
|
270
|
+
rootCauses.unsizedImages.forEach(img => {
|
271
|
+
// TODO(b/413284569): if we store a nice human readable name for this
|
272
|
+
// image in the trace metadata, we can do something much nicer here.
|
273
|
+
const url = img.paintImageEvent.args.data.url;
|
274
|
+
const nodeName = img.paintImageEvent.args.data.nodeName;
|
275
|
+
const extraText = url ? `url: ${this.#formatUrl(url)}` : `id: ${img.backendNodeId}`;
|
276
|
+
potentialRootCauses.push(`- An unsized image (${nodeName}) (${extraText}).`);
|
277
|
+
});
|
278
|
+
}
|
279
|
+
const rootCauseText = potentialRootCauses.length ? `- Potential root causes:\n ${potentialRootCauses.join('\n')}` :
|
280
|
+
'- No potential root causes identified';
|
281
|
+
|
282
|
+
const startTime = Trace.Helpers.Timing.microToMilli(Trace.Types.Timing.Micro(shift.ts - baseTime));
|
283
|
+
return `### Layout shift ${index + 1}:
|
284
|
+
- Start time: ${millis(startTime)}
|
285
|
+
- Score: ${shift.args.data?.weighted_score_delta.toFixed(4)}
|
286
|
+
${rootCauseText}`;
|
287
|
+
}
|
288
|
+
|
215
289
|
/**
|
216
290
|
* Create an AI prompt string out of the CLS Culprits Insight model to use with Ask AI.
|
217
291
|
* @param insight The CLS Culprits Model to query.
|
@@ -220,7 +294,7 @@ export class PerformanceInsightFormatter extends PerformanceTraceFormatter {
|
|
220
294
|
formatClsCulpritsInsight(insight: Trace.Insights.Models.CLSCulprits.CLSCulpritsInsightModel): string {
|
221
295
|
const {worstCluster, shifts} = insight;
|
222
296
|
if (!worstCluster) {
|
223
|
-
return '';
|
297
|
+
return 'No layout shifts were found.';
|
224
298
|
}
|
225
299
|
|
226
300
|
const baseTime = this.#parsedTrace.data.Meta.traceBounds.min;
|
@@ -231,7 +305,7 @@ export class PerformanceInsightFormatter extends PerformanceTraceFormatter {
|
|
231
305
|
} as const;
|
232
306
|
|
233
307
|
const shiftsFormatted = worstCluster.events.map((layoutShift, index) => {
|
234
|
-
return
|
308
|
+
return this.#formatLayoutShift(layoutShift, index, shifts.get(layoutShift));
|
235
309
|
});
|
236
310
|
|
237
311
|
return `The worst layout shift cluster was the cluster that started at ${
|
@@ -272,7 +346,7 @@ ${shiftsFormatted.join('\n')}`;
|
|
272
346
|
|
273
347
|
return `${this.#lcpMetricSharedContext()}
|
274
348
|
|
275
|
-
${this.formatNetworkRequests([documentRequest], {
|
349
|
+
${this.#traceFormatter.formatNetworkRequests([documentRequest], {
|
276
350
|
verbose: true,
|
277
351
|
customTitle: 'Document network request'
|
278
352
|
})}
|
@@ -384,8 +458,9 @@ Duplication grouped by Node modules: ${filesFormatted}`;
|
|
384
458
|
const url = new Common.ParsedURL.ParsedURL(font.request.args.data.url);
|
385
459
|
fontName = url.isValid ? url.lastPathComponent : '(not available)';
|
386
460
|
}
|
387
|
-
output += `\n - Font name: ${fontName}, URL: ${
|
388
|
-
font.display}', Wasted time: ${
|
461
|
+
output += `\n - Font name: ${fontName}, URL: ${
|
462
|
+
this.#formatRequestUrl(font.request)}, Property 'font-display' set to: '${font.display}', Wasted time: ${
|
463
|
+
this.#formatMilli(font.wastedTime)}.`;
|
389
464
|
}
|
390
465
|
|
391
466
|
output += '\n\n' + Trace.Insights.Models.FontDisplay.UIStrings.description;
|
@@ -469,7 +544,7 @@ Duplication grouped by Node modules: ${filesFormatted}`;
|
|
469
544
|
})
|
470
545
|
.join('\n');
|
471
546
|
|
472
|
-
return `### ${image.request
|
547
|
+
return `### ${this.#formatRequestUrl(image.request)}
|
473
548
|
- Potential savings: ${bytes(image.byteSavings)}
|
474
549
|
- Optimizations:\n${optimizations}`;
|
475
550
|
})
|
@@ -580,7 +655,9 @@ ${checklistBulletPoints.map(point => `- ${point.name}: ${point.passed ? 'PASSED'
|
|
580
655
|
|
581
656
|
const filesFormatted =
|
582
657
|
Array.from(legacyJavaScriptResults)
|
583
|
-
.map(
|
658
|
+
.map(
|
659
|
+
([script, result]) =>
|
660
|
+
`\n- Script: ${this.#formatScriptUrl(script)} - Wasted bytes: ${result.estimatedByteSavings} bytes
|
584
661
|
Matches:
|
585
662
|
${result.matches.map(match => `Line: ${match.line}, Column: ${match.column}, Name: ${match.name}`).join('\n')}`)
|
586
663
|
.join('\n');
|
@@ -598,8 +675,8 @@ ${filesFormatted}`;
|
|
598
675
|
*/
|
599
676
|
formatModernHttpInsight(insight: Trace.Insights.Models.ModernHTTP.ModernHTTPInsightModel): string {
|
600
677
|
const requestSummary = (insight.http1Requests.length === 1) ?
|
601
|
-
this.formatNetworkRequests(insight.http1Requests, {verbose: true}) :
|
602
|
-
this.formatNetworkRequests(insight.http1Requests);
|
678
|
+
this.#traceFormatter.formatNetworkRequests(insight.http1Requests, {verbose: true}) :
|
679
|
+
this.#traceFormatter.formatNetworkRequests(insight.http1Requests);
|
603
680
|
|
604
681
|
if (requestSummary.length === 0) {
|
605
682
|
return 'There are no requests that were served over a legacy HTTP protocol.';
|
@@ -631,7 +708,7 @@ ${requestSummary}`;
|
|
631
708
|
function formatNode(
|
632
709
|
this: PerformanceInsightFormatter, node: Trace.Insights.Models.NetworkDependencyTree.CriticalRequestNode,
|
633
710
|
indent: string): string {
|
634
|
-
const url = node.request
|
711
|
+
const url = this.#formatRequestUrl(node.request);
|
635
712
|
const time = this.#formatMicro(node.timeFromInitialRequest);
|
636
713
|
const isLongest = node.isLongest ? ' (longest chain)' : '';
|
637
714
|
let nodeString = `${indent}- ${url} (${time})${isLongest}\n`;
|
@@ -696,7 +773,7 @@ ${requestSummary}`;
|
|
696
773
|
* @returns a string formatted for sending to Ask AI.
|
697
774
|
*/
|
698
775
|
formatRenderBlockingInsight(insight: Trace.Insights.Models.RenderBlocking.RenderBlockingInsightModel): string {
|
699
|
-
const requestSummary = this.formatNetworkRequests(insight.renderBlockingRequests);
|
776
|
+
const requestSummary = this.#traceFormatter.formatNetworkRequests(insight.renderBlockingRequests);
|
700
777
|
|
701
778
|
if (requestSummary.length === 0) {
|
702
779
|
return 'There are no network requests that are render blocking.';
|
@@ -934,7 +1011,7 @@ ${this.#links()}`;
|
|
934
1011
|
#links(): string {
|
935
1012
|
switch (this.#insight.insightKey) {
|
936
1013
|
case 'CLSCulprits':
|
937
|
-
return `- https://
|
1014
|
+
return `- https://web.dev/articles/cls
|
938
1015
|
- https://web.dev/articles/optimize-cls`;
|
939
1016
|
case 'DocumentLatency':
|
940
1017
|
return '- https://web.dev/articles/optimize-ttfb';
|
@@ -1065,45 +1142,3 @@ Polyfills and transforms enable older browsers to use new JavaScript features. H
|
|
1065
1142
|
}
|
1066
1143
|
}
|
1067
1144
|
}
|
1068
|
-
|
1069
|
-
export class TraceEventFormatter {
|
1070
|
-
static layoutShift(
|
1071
|
-
shift: Trace.Types.Events.SyntheticLayoutShift, index: number, parsedTrace: Trace.TraceModel.ParsedTrace,
|
1072
|
-
rootCauses?: Trace.Insights.Models.CLSCulprits.LayoutShiftRootCausesData): string {
|
1073
|
-
const baseTime = parsedTrace.data.Meta.traceBounds.min;
|
1074
|
-
|
1075
|
-
const potentialRootCauses: string[] = [];
|
1076
|
-
if (rootCauses) {
|
1077
|
-
rootCauses.iframes.forEach(
|
1078
|
-
iframe => potentialRootCauses.push(
|
1079
|
-
`An iframe (id: ${iframe.frame}, url: ${iframe.url ?? 'unknown'} was injected into the page)`));
|
1080
|
-
rootCauses.webFonts.forEach(req => {
|
1081
|
-
potentialRootCauses.push(`A font that was loaded over the network (${req.args.data.url}).`);
|
1082
|
-
});
|
1083
|
-
// TODO(b/413285103): use the nice strings for non-composited animations.
|
1084
|
-
// The code for this lives in TimelineUIUtils but that cannot be used
|
1085
|
-
// within models. We should move it and then expose the animations info
|
1086
|
-
// more nicely.
|
1087
|
-
rootCauses.nonCompositedAnimations.forEach(_ => {
|
1088
|
-
potentialRootCauses.push('A non composited animation.');
|
1089
|
-
});
|
1090
|
-
rootCauses.unsizedImages.forEach(img => {
|
1091
|
-
// TODO(b/413284569): if we store a nice human readable name for this
|
1092
|
-
// image in the trace metadata, we can do something much nicer here.
|
1093
|
-
const url = img.paintImageEvent.args.data.url;
|
1094
|
-
const nodeName = img.paintImageEvent.args.data.nodeName;
|
1095
|
-
const extraText = url ? `url: ${url}` : `id: ${img.backendNodeId}`;
|
1096
|
-
potentialRootCauses.push(`An unsized image (${nodeName}) (${extraText}).`);
|
1097
|
-
});
|
1098
|
-
}
|
1099
|
-
const rootCauseText = potentialRootCauses.length ?
|
1100
|
-
`- Potential root causes:\n - ${potentialRootCauses.join('\n - ')}` :
|
1101
|
-
'- No potential root causes identified';
|
1102
|
-
|
1103
|
-
const startTime = Trace.Helpers.Timing.microToMilli(Trace.Types.Timing.Micro(shift.ts - baseTime));
|
1104
|
-
return `### Layout shift ${index + 1}:
|
1105
|
-
- Start time: ${millis(startTime)}
|
1106
|
-
- Score: ${shift.args.data?.weighted_score_delta.toFixed(4)}
|
1107
|
-
${rootCauseText}`;
|
1108
|
-
}
|
1109
|
-
}
|