chrome-devtools-frontend 1.0.1526630 → 1.0.1529186
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/docs/ui_engineering.md +159 -0
- package/eslint.config.mjs +6 -1
- package/front_end/core/host/UserMetrics.ts +2 -1
- package/front_end/core/i18n/i18nImpl.ts +6 -1
- package/front_end/core/protocol_client/protocol_client.ts +1 -1
- package/front_end/core/root/Runtime.ts +38 -4
- package/front_end/core/sdk/CSSMatchedStyles.ts +50 -7
- package/front_end/core/sdk/CSSRule.ts +35 -6
- package/front_end/core/sdk/Connections.ts +2 -1
- package/front_end/core/sdk/DOMModel.ts +4 -0
- package/front_end/core/sdk/DebuggerModel.ts +5 -1
- package/front_end/core/sdk/NetworkManager.ts +267 -34
- package/front_end/core/sdk/PreloadingModel.ts +82 -17
- package/front_end/core/sdk/RehydratingConnection.snapshot.txt +1 -1
- package/front_end/core/sdk/RehydratingConnection.ts +29 -4
- package/front_end/core/sdk/ScopeTreeCache.ts +8 -3
- package/front_end/core/sdk/SourceMap.ts +41 -11
- package/front_end/core/sdk/SourceMapManager.ts +13 -2
- package/front_end/core/sdk/SourceMapScopesInfo.ts +49 -2
- package/front_end/core/sdk/TargetManager.ts +0 -22
- package/front_end/core/sdk/TraceObject.ts +8 -7
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +81 -0
- package/front_end/entrypoints/inspector_main/InspectorMain.ts +3 -1
- package/front_end/entrypoints/main/GlobalAiButton.ts +1 -0
- package/front_end/entrypoints/main/MainImpl.ts +42 -28
- package/front_end/generated/InspectorBackendCommands.js +3 -2
- package/front_end/generated/SupportedCSSProperties.js +2 -0
- package/front_end/generated/protocol.ts +17 -3
- package/front_end/models/ai_assistance/BuiltInAi.ts +111 -0
- package/front_end/models/ai_assistance/ConversationHandler.ts +15 -14
- package/front_end/models/ai_assistance/ai_assistance.ts +53 -24
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.snapshot.txt +105 -0
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +6 -1
- package/front_end/models/extensions/ExtensionView.ts +3 -0
- package/front_end/models/javascript_metadata/NativeFunctions.js +31 -27
- package/front_end/models/live-metrics/web-vitals-injected/web-vitals-injected.ts +31 -29
- package/front_end/models/persistence/NetworkPersistenceManager.ts +3 -5
- package/front_end/models/persistence/PersistenceImpl.ts +0 -5
- package/front_end/models/persistence/persistence-meta.ts +0 -31
- package/front_end/models/persistence/persistence.ts +0 -6
- package/front_end/models/source_map_scopes/NamesResolver.ts +5 -11
- package/front_end/models/stack_trace/Trie.ts +9 -0
- package/front_end/models/trace/lantern/types/Lantern.ts +1 -1
- package/front_end/panels/accessibility/AXBreadcrumbsPane.ts +1 -0
- package/front_end/panels/accessibility/AccessibilitySidebarView.ts +1 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +120 -113
- package/front_end/panels/ai_assistance/PatchWidget.ts +9 -8
- package/front_end/panels/ai_assistance/SelectWorkspaceDialog.ts +2 -0
- package/front_end/panels/ai_assistance/components/ChatView.ts +29 -29
- package/front_end/panels/ai_assistance/components/UserActionRow.ts +1 -0
- package/front_end/panels/animation/AnimationTimeline.ts +1 -0
- package/front_end/panels/application/CookieItemsView.ts +1 -0
- package/front_end/panels/application/KeyValueStorageItemsView.ts +1 -0
- package/front_end/panels/application/ServiceWorkerCacheViews.ts +2 -0
- package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +11 -5
- package/front_end/panels/application/preloading/components/PreloadingMismatchedHeadersGrid.ts +2 -2
- package/front_end/panels/application/preloading/components/PreloadingString.ts +7 -5
- package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +22 -10
- package/front_end/panels/changes/CombinedDiffView.ts +1 -0
- package/front_end/{models/persistence → panels/common}/PersistenceUtils.ts +15 -17
- package/front_end/panels/common/common.ts +1 -0
- package/front_end/panels/console/ConsoleInsightTeaser.ts +369 -0
- package/front_end/panels/console/ConsolePanel.ts +2 -0
- package/front_end/panels/console/ConsolePrompt.ts +12 -2
- package/front_end/panels/console/ConsoleSidebar.ts +1 -1
- package/front_end/panels/console/ConsoleView.ts +12 -0
- package/front_end/panels/console/ConsoleViewMessage.ts +44 -0
- package/front_end/panels/{explain → console}/PromptBuilder.ts +12 -7
- package/front_end/panels/console/console-meta.ts +14 -0
- package/front_end/panels/console/console.ts +6 -0
- package/front_end/panels/console/consoleInsightTeaser.css +83 -0
- package/front_end/panels/coverage/CoverageListView.ts +29 -11
- package/front_end/panels/coverage/CoverageView.ts +292 -284
- package/front_end/panels/coverage/coverageView.css +17 -0
- package/front_end/panels/elements/ComputedStyleWidget.ts +1 -0
- package/front_end/panels/elements/LayoutPane.ts +1 -0
- package/front_end/panels/elements/NodeStackTraceWidget.ts +1 -0
- package/front_end/panels/elements/StylePropertyTreeElement.ts +5 -1
- package/front_end/panels/elements/stylePropertiesTreeOutline.css +17 -0
- package/front_end/panels/emulation/DeviceModeView.ts +2 -0
- package/front_end/panels/explain/ActionDelegate.ts +4 -2
- package/front_end/panels/explain/components/ConsoleInsight.ts +14 -12
- package/front_end/panels/explain/explain-meta.ts +7 -0
- package/front_end/panels/explain/explain.ts +0 -1
- package/front_end/panels/js_timeline/js_timeline-meta.ts +1 -1
- package/front_end/panels/layer_viewer/Layers3DView.ts +2 -0
- package/front_end/panels/lighthouse/LighthouseReportSelector.ts +1 -0
- package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorPane.ts +1 -0
- package/front_end/panels/media/MainView.ts +1 -0
- package/front_end/panels/media/TickingFlameChart.ts +2 -0
- package/front_end/panels/network/BlockedURLsPane.ts +237 -108
- package/front_end/panels/network/EventSourceMessagesView.ts +1 -0
- package/front_end/panels/network/NetworkItemView.ts +1 -0
- package/front_end/panels/network/NetworkLogView.ts +9 -7
- package/front_end/panels/network/NetworkOverview.ts +1 -0
- package/front_end/panels/network/RequestCookiesView.ts +1 -0
- package/front_end/panels/network/RequestHTMLView.ts +1 -0
- package/front_end/panels/network/RequestInitiatorView.ts +1 -0
- package/front_end/panels/network/RequestPayloadView.ts +1 -0
- package/front_end/panels/network/RequestPreviewView.ts +1 -0
- package/front_end/panels/network/RequestResponseView.ts +1 -0
- package/front_end/panels/network/RequestTimingView.ts +2 -0
- package/front_end/panels/network/ResourceDirectSocketChunkView.ts +1 -0
- package/front_end/panels/network/ResourceWebSocketFrameView.ts +1 -0
- package/front_end/panels/network/components/RequestHeadersView.ts +2 -0
- package/front_end/panels/network/components/RequestTrustTokensView.ts +2 -0
- package/front_end/panels/performance_monitor/PerformanceMonitor.ts +2 -0
- package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +2 -0
- package/front_end/panels/profiler/HeapSnapshotView.ts +7 -0
- package/front_end/panels/profiler/IsolateSelector.ts +1 -0
- package/front_end/panels/profiler/LiveHeapProfileView.ts +1 -0
- package/front_end/panels/profiler/ProfileView.ts +1 -0
- package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +1 -0
- package/front_end/panels/recorder/RecorderPanel.ts +2 -0
- package/front_end/panels/screencast/ScreencastView.ts +1 -0
- package/front_end/panels/search/SearchView.ts +1 -0
- package/front_end/panels/settings/AISettingsTab.ts +3 -3
- package/front_end/{models/persistence → panels/settings}/EditFileSystemView.ts +3 -6
- package/front_end/panels/settings/WorkspaceSettingsTab.ts +4 -1
- package/front_end/panels/settings/emulation/components/UserAgentClientHintsForm.ts +2 -2
- package/front_end/panels/settings/settings.ts +2 -0
- package/front_end/panels/sources/AiCodeCompletionPlugin.ts +12 -0
- package/front_end/panels/sources/BreakpointsView.ts +1 -0
- package/front_end/panels/sources/DebuggerPlugin.ts +1 -0
- package/front_end/{models/persistence → panels/sources}/PersistenceActions.ts +8 -12
- package/front_end/panels/sources/TabbedEditorContainer.ts +2 -1
- package/front_end/panels/sources/UISourceCodeFrame.ts +17 -2
- package/front_end/panels/sources/sources-meta.ts +15 -0
- package/front_end/panels/sources/sources.ts +2 -0
- package/front_end/panels/timeline/README.md +2 -2
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +1 -1
- package/front_end/panels/timeline/TimelineFlameChartView.ts +4 -3
- package/front_end/panels/timeline/TimelineLayersView.ts +1 -0
- package/front_end/panels/timeline/TimelinePaintProfilerView.ts +114 -37
- package/front_end/panels/timeline/TimelinePanel.ts +43 -62
- package/front_end/panels/timeline/TimelineTreeView.ts +1 -0
- package/front_end/panels/timeline/components/LiveMetricsView.ts +4 -8
- package/front_end/panels/timeline/components/Sidebar.ts +2 -0
- package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +1 -1
- package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +7 -7
- package/front_end/panels/timeline/overlays/OverlaysImpl.ts +1 -1
- package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +4 -4
- package/front_end/panels/utils/utils.ts +2 -1
- package/front_end/panels/web_audio/WebAudioView.ts +1 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/diff/diff_match_patch.js +1 -1
- package/front_end/third_party/lighthouse/README.chromium +2 -2
- package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1530 -2426
- package/front_end/third_party/lighthouse/locales/ar-XB.json +107 -455
- package/front_end/third_party/lighthouse/locales/ar.json +107 -455
- package/front_end/third_party/lighthouse/locales/bg.json +96 -444
- package/front_end/third_party/lighthouse/locales/ca.json +96 -444
- package/front_end/third_party/lighthouse/locales/cs.json +96 -444
- package/front_end/third_party/lighthouse/locales/da.json +96 -444
- package/front_end/third_party/lighthouse/locales/de.json +96 -444
- package/front_end/third_party/lighthouse/locales/el.json +96 -444
- package/front_end/third_party/lighthouse/locales/en-GB.json +96 -444
- package/front_end/third_party/lighthouse/locales/en-US.json +116 -467
- package/front_end/third_party/lighthouse/locales/en-XA.json +93 -441
- package/front_end/third_party/lighthouse/locales/en-XL.json +116 -467
- package/front_end/third_party/lighthouse/locales/es-419.json +96 -444
- package/front_end/third_party/lighthouse/locales/es.json +96 -444
- package/front_end/third_party/lighthouse/locales/fi.json +96 -444
- package/front_end/third_party/lighthouse/locales/fil.json +96 -444
- package/front_end/third_party/lighthouse/locales/fr.json +96 -444
- package/front_end/third_party/lighthouse/locales/he.json +118 -466
- package/front_end/third_party/lighthouse/locales/hi.json +96 -444
- package/front_end/third_party/lighthouse/locales/hr.json +100 -448
- package/front_end/third_party/lighthouse/locales/hu.json +96 -444
- package/front_end/third_party/lighthouse/locales/id.json +96 -444
- package/front_end/third_party/lighthouse/locales/it.json +96 -444
- package/front_end/third_party/lighthouse/locales/ja.json +96 -444
- package/front_end/third_party/lighthouse/locales/ko.json +97 -445
- package/front_end/third_party/lighthouse/locales/lt.json +96 -444
- package/front_end/third_party/lighthouse/locales/lv.json +97 -445
- package/front_end/third_party/lighthouse/locales/nl.json +96 -444
- package/front_end/third_party/lighthouse/locales/no.json +96 -444
- package/front_end/third_party/lighthouse/locales/pl.json +96 -444
- package/front_end/third_party/lighthouse/locales/pt-PT.json +96 -444
- package/front_end/third_party/lighthouse/locales/pt.json +97 -445
- package/front_end/third_party/lighthouse/locales/ro.json +97 -445
- package/front_end/third_party/lighthouse/locales/ru.json +96 -444
- package/front_end/third_party/lighthouse/locales/sk.json +96 -444
- package/front_end/third_party/lighthouse/locales/sl.json +96 -444
- package/front_end/third_party/lighthouse/locales/sr-Latn.json +96 -444
- package/front_end/third_party/lighthouse/locales/sr.json +96 -444
- package/front_end/third_party/lighthouse/locales/sv.json +96 -444
- package/front_end/third_party/lighthouse/locales/ta.json +96 -444
- package/front_end/third_party/lighthouse/locales/te.json +97 -445
- package/front_end/third_party/lighthouse/locales/th.json +96 -444
- package/front_end/third_party/lighthouse/locales/tr.json +96 -444
- package/front_end/third_party/lighthouse/locales/uk.json +96 -444
- package/front_end/third_party/lighthouse/locales/vi.json +96 -444
- package/front_end/third_party/lighthouse/locales/zh-HK.json +96 -444
- package/front_end/third_party/lighthouse/locales/zh-TW.json +97 -445
- package/front_end/third_party/lighthouse/locales/zh.json +96 -444
- package/front_end/third_party/lighthouse/report/bundle.d.ts +8 -14
- package/front_end/third_party/lighthouse/report/bundle.js +10 -49
- package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +1 -1
- package/front_end/third_party/web-vitals/README.chromium +5 -8
- package/front_end/third_party/web-vitals/package/README.md +191 -152
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/index.d.ts +0 -1
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/index.js +0 -1
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onCLS.d.ts +2 -2
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onCLS.js +45 -26
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFCP.d.ts +2 -2
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFCP.js +3 -3
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onINP.d.ts +10 -10
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onINP.js +307 -206
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onLCP.d.ts +2 -2
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onLCP.js +69 -49
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onTTFB.d.ts +2 -2
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onTTFB.js +2 -2
- package/front_end/third_party/web-vitals/package/dist/modules/index.d.ts +0 -1
- package/front_end/third_party/web-vitals/package/dist/modules/index.js +0 -1
- package/front_end/third_party/web-vitals/package/dist/modules/lib/InteractionManager.d.ts +33 -0
- package/front_end/third_party/web-vitals/package/dist/modules/lib/InteractionManager.js +111 -0
- package/front_end/third_party/web-vitals/package/dist/modules/lib/LCPEntryManager.d.ts +4 -0
- package/front_end/third_party/web-vitals/package/dist/modules/{attribution/deprecated.js → lib/LCPEntryManager.js} +6 -7
- package/front_end/third_party/web-vitals/package/dist/modules/lib/LayoutShiftManager.d.ts +6 -0
- package/front_end/third_party/web-vitals/package/dist/modules/lib/LayoutShiftManager.js +44 -0
- package/front_end/third_party/web-vitals/package/dist/modules/lib/bindReporter.js +1 -1
- package/front_end/third_party/web-vitals/package/dist/modules/lib/generateUniqueID.js +1 -1
- package/front_end/third_party/web-vitals/package/dist/modules/lib/getActivationStart.js +1 -1
- package/front_end/third_party/web-vitals/package/dist/modules/lib/getNavigationEntry.js +5 -7
- package/front_end/third_party/web-vitals/package/dist/modules/lib/getSelector.d.ts +1 -1
- package/front_end/third_party/web-vitals/package/dist/modules/lib/getSelector.js +9 -12
- package/front_end/third_party/web-vitals/package/dist/modules/lib/getVisibilityWatcher.d.ts +1 -0
- package/front_end/third_party/web-vitals/package/dist/modules/lib/getVisibilityWatcher.js +52 -33
- package/front_end/third_party/web-vitals/package/dist/modules/lib/initMetric.d.ts +0 -2
- package/front_end/third_party/web-vitals/package/dist/modules/lib/initMetric.js +2 -2
- package/front_end/third_party/web-vitals/package/dist/modules/lib/initUnique.d.ts +6 -0
- package/front_end/third_party/web-vitals/package/dist/modules/{deprecated.js → lib/initUnique.js} +11 -4
- package/front_end/third_party/web-vitals/package/dist/modules/lib/observe.js +3 -6
- package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/interactionCountPolyfill.js +6 -6
- package/front_end/third_party/web-vitals/package/dist/modules/lib/{whenIdle.d.ts → whenIdleOrHidden.d.ts} +1 -1
- package/front_end/third_party/web-vitals/package/dist/modules/lib/{whenIdle.js → whenIdleOrHidden.js} +10 -8
- package/front_end/third_party/web-vitals/package/dist/modules/onCLS.js +17 -35
- package/front_end/third_party/web-vitals/package/dist/modules/onFCP.js +3 -5
- package/front_end/third_party/web-vitals/package/dist/modules/onINP.d.ts +9 -7
- package/front_end/third_party/web-vitals/package/dist/modules/onINP.js +27 -19
- package/front_end/third_party/web-vitals/package/dist/modules/onLCP.js +33 -26
- package/front_end/third_party/web-vitals/package/dist/modules/onTTFB.js +2 -4
- package/front_end/third_party/web-vitals/package/dist/modules/types/base.d.ts +6 -5
- package/front_end/third_party/web-vitals/package/dist/modules/types/cls.d.ts +5 -3
- package/front_end/third_party/web-vitals/package/dist/modules/types/inp.d.ts +80 -33
- package/front_end/third_party/web-vitals/package/dist/modules/types/lcp.d.ts +6 -2
- package/front_end/third_party/web-vitals/package/dist/modules/types.d.ts +28 -4
- package/front_end/third_party/web-vitals/package/dist/modules/types.js +0 -1
- package/front_end/third_party/web-vitals/package/package.json +4 -10
- package/front_end/third_party/web-vitals/package/src/attribution/index.ts +0 -1
- package/front_end/third_party/web-vitals/package/src/attribution/onCLS.ts +58 -33
- package/front_end/third_party/web-vitals/package/src/attribution/onFCP.ts +4 -4
- package/front_end/third_party/web-vitals/package/src/attribution/onINP.ts +382 -258
- package/front_end/third_party/web-vitals/package/src/attribution/onLCP.ts +96 -69
- package/front_end/third_party/web-vitals/package/src/attribution/onTTFB.ts +3 -3
- package/front_end/third_party/web-vitals/package/src/index.ts +0 -1
- package/front_end/third_party/web-vitals/package/src/lib/InteractionManager.ts +146 -0
- package/front_end/third_party/web-vitals/package/src/{attribution/deprecated.ts → lib/LCPEntryManager.ts} +6 -9
- package/front_end/third_party/web-vitals/package/src/lib/LayoutShiftManager.ts +50 -0
- package/front_end/third_party/web-vitals/package/src/lib/bindReporter.ts +1 -1
- package/front_end/third_party/web-vitals/package/src/lib/generateUniqueID.ts +1 -1
- package/front_end/third_party/web-vitals/package/src/lib/getActivationStart.ts +1 -1
- package/front_end/third_party/web-vitals/package/src/lib/getNavigationEntry.ts +5 -8
- package/front_end/third_party/web-vitals/package/src/lib/getSelector.ts +12 -12
- package/front_end/third_party/web-vitals/package/src/lib/getVisibilityWatcher.ts +57 -35
- package/front_end/third_party/web-vitals/package/src/lib/initMetric.ts +2 -2
- package/front_end/third_party/web-vitals/package/src/{deprecated.ts → lib/initUnique.ts} +14 -8
- package/front_end/third_party/web-vitals/package/src/lib/observe.ts +3 -11
- package/front_end/third_party/web-vitals/package/src/lib/polyfills/interactionCountPolyfill.ts +12 -6
- package/front_end/third_party/web-vitals/package/src/lib/{whenIdle.ts → whenIdleOrHidden.ts} +10 -8
- package/front_end/third_party/web-vitals/package/src/onCLS.ts +17 -38
- package/front_end/third_party/web-vitals/package/src/onFCP.ts +3 -6
- package/front_end/third_party/web-vitals/package/src/onINP.ts +33 -28
- package/front_end/third_party/web-vitals/package/src/onLCP.ts +36 -29
- package/front_end/third_party/web-vitals/package/src/onTTFB.ts +2 -5
- package/front_end/third_party/web-vitals/package/src/types/base.ts +5 -5
- package/front_end/third_party/web-vitals/package/src/types/cls.ts +5 -3
- package/front_end/third_party/web-vitals/package/src/types/inp.ts +88 -33
- package/front_end/third_party/web-vitals/package/src/types/lcp.ts +6 -2
- package/front_end/third_party/web-vitals/package/src/types.ts +47 -4
- package/front_end/third_party/web-vitals/patches/0001-Add-onEachInteraction-to-onINP-options.patch +75 -0
- package/front_end/third_party/web-vitals/rebuild.sh +32 -18
- package/front_end/third_party/web-vitals/web-vitals-tsconfig.json +5 -10
- package/front_end/third_party/web-vitals/web-vitals.ts +0 -2
- package/front_end/ui/components/docs/console_insight/basic.ts +3 -2
- package/front_end/ui/components/legacy_wrapper/LegacyWrapper.ts +2 -0
- package/front_end/ui/components/text_editor/TextEditor.ts +0 -2
- package/front_end/ui/legacy/InspectorView.ts +2 -0
- package/front_end/ui/legacy/ListWidget.ts +2 -2
- package/front_end/ui/legacy/SplitWidget.ts +2 -0
- package/front_end/ui/legacy/TabbedPane.ts +1 -0
- package/front_end/ui/legacy/TargetCrashedScreen.ts +1 -0
- package/front_end/ui/legacy/UIUtils.ts +8 -19
- package/front_end/ui/legacy/ViewManager.ts +1 -0
- package/front_end/ui/legacy/components/color_picker/FormatPickerContextMenu.ts +7 -20
- package/front_end/ui/legacy/components/color_picker/Spectrum.ts +2 -0
- package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +1 -0
- package/front_end/ui/legacy/components/inline_editor/BezierEditor.ts +1 -0
- package/front_end/ui/legacy/components/perf_ui/ChartViewport.ts +1 -0
- package/front_end/ui/legacy/components/quick_open/FilteredListWidget.ts +1 -0
- package/front_end/ui/legacy/components/source_frame/FontView.ts +1 -0
- package/front_end/ui/legacy/components/source_frame/ImageView.ts +1 -0
- package/front_end/ui/legacy/components/source_frame/JSONView.ts +1 -0
- package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +1 -0
- package/front_end/ui/legacy/components/source_frame/StreamingContentHexView.ts +2 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +25 -0
- package/mcp/README.md +7 -0
- package/mcp/mcp.ts +8 -0
- package/package.json +1 -1
- package/front_end/models/live-metrics/web-vitals-injected/OnEachInteraction.ts +0 -34
- package/front_end/third_party/web-vitals/package/attribution.d.ts +0 -16
- package/front_end/third_party/web-vitals/package/attribution.js +0 -18
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/deprecated.d.ts +0 -7
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFID.d.ts +0 -11
- package/front_end/third_party/web-vitals/package/dist/modules/attribution/onFID.js +0 -46
- package/front_end/third_party/web-vitals/package/dist/modules/deprecated.d.ts +0 -5
- package/front_end/third_party/web-vitals/package/dist/modules/lib/interactions.d.ts +0 -31
- package/front_end/third_party/web-vitals/package/dist/modules/lib/interactions.js +0 -107
- package/front_end/third_party/web-vitals/package/dist/modules/lib/onHidden.d.ts +0 -1
- package/front_end/third_party/web-vitals/package/dist/modules/lib/onHidden.js +0 -22
- package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/firstInputPolyfill.d.ts +0 -7
- package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/firstInputPolyfill.js +0 -147
- package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/getFirstHiddenTimePolyfill.d.ts +0 -1
- package/front_end/third_party/web-vitals/package/dist/modules/lib/polyfills/getFirstHiddenTimePolyfill.js +0 -25
- package/front_end/third_party/web-vitals/package/dist/modules/onFID.d.ts +0 -13
- package/front_end/third_party/web-vitals/package/dist/modules/onFID.js +0 -70
- package/front_end/third_party/web-vitals/package/dist/modules/types/fid.d.ts +0 -46
- package/front_end/third_party/web-vitals/package/dist/modules/types/fid.js +0 -16
- package/front_end/third_party/web-vitals/package/src/attribution/onFID.ts +0 -62
- package/front_end/third_party/web-vitals/package/src/lib/interactions.ts +0 -139
- package/front_end/third_party/web-vitals/package/src/lib/onHidden.ts +0 -23
- package/front_end/third_party/web-vitals/package/src/lib/polyfills/firstInputPolyfill.ts +0 -174
- package/front_end/third_party/web-vitals/package/src/onFID.ts +0 -105
- package/front_end/third_party/web-vitals/package/src/types/fid.ts +0 -65
- package/front_end/ui/components/text_editor/textEditor.css +0 -18
- package/front_end/ui/legacy/inlineButton.css +0 -22
- /package/front_end/entrypoints/{rehydrated_devtools_app/rehydrated_devtools_app.ts → trace_app/trace_app.ts} +0 -0
- /package/front_end/{models/persistence → panels/settings}/editFileSystemView.css +0 -0
|
@@ -16,19 +16,17 @@
|
|
|
16
16
|
|
|
17
17
|
import {getLoadState} from '../lib/getLoadState.js';
|
|
18
18
|
import {getSelector} from '../lib/getSelector.js';
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
entryPreProcessingCallbacks,
|
|
22
|
-
longestInteractionMap,
|
|
23
|
-
} from '../lib/interactions.js';
|
|
19
|
+
import {initUnique} from '../lib/initUnique.js';
|
|
20
|
+
import {InteractionManager, Interaction} from '../lib/InteractionManager.js';
|
|
24
21
|
import {observe} from '../lib/observe.js';
|
|
25
|
-
import {
|
|
22
|
+
import {whenIdleOrHidden} from '../lib/whenIdleOrHidden.js';
|
|
26
23
|
import {onINP as unattributedOnINP} from '../onINP.js';
|
|
27
24
|
import {
|
|
28
25
|
INPAttribution,
|
|
26
|
+
INPAttributionReportOpts,
|
|
29
27
|
INPMetric,
|
|
30
28
|
INPMetricWithAttribution,
|
|
31
|
-
|
|
29
|
+
INPLongestScriptSummary,
|
|
32
30
|
} from '../types.js';
|
|
33
31
|
|
|
34
32
|
interface pendingEntriesGroup {
|
|
@@ -48,289 +46,415 @@ interface pendingEntriesGroup {
|
|
|
48
46
|
// keeping the most recent 50 should be more than sufficient.
|
|
49
47
|
const MAX_PREVIOUS_FRAMES = 50;
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Calculates the [INP](https://web.dev/articles/inp) value for the current
|
|
51
|
+
* page and calls the `callback` function once the value is ready, along with
|
|
52
|
+
* the `event` performance entries reported for that interaction. The reported
|
|
53
|
+
* value is a `DOMHighResTimeStamp`.
|
|
54
|
+
*
|
|
55
|
+
* A custom `durationThreshold` configuration option can optionally be passed
|
|
56
|
+
* to control what `event-timing` entries are considered for INP reporting. The
|
|
57
|
+
* default threshold is `40`, which means INP scores of less than 40 will not
|
|
58
|
+
* be reported. To avoid reporting no interactions in these cases, the library
|
|
59
|
+
* will fall back to the input delay of the first interaction. Note that this
|
|
60
|
+
* will not affect your 75th percentile INP value unless that value is also
|
|
61
|
+
* less than 40 (well below the recommended
|
|
62
|
+
* [good](https://web.dev/articles/inp#what_is_a_good_inp_score) threshold).
|
|
63
|
+
*
|
|
64
|
+
* If the `reportAllChanges` configuration option is set to `true`, the
|
|
65
|
+
* `callback` function will be called as soon as the value is initially
|
|
66
|
+
* determined as well as any time the value changes throughout the page
|
|
67
|
+
* lifespan.
|
|
68
|
+
*
|
|
69
|
+
* _**Important:** INP should be continually monitored for changes throughout
|
|
70
|
+
* the entire lifespan of a page—including if the user returns to the page after
|
|
71
|
+
* it has been hidden/backgrounded. However, since browsers often [will not fire
|
|
72
|
+
* additional callbacks once the user has backgrounded a
|
|
73
|
+
* page](https://developer.chrome.com/blog/page-lifecycle-api/#advice-hidden),
|
|
74
|
+
* `callback` is always called when the page's visibility state changes to
|
|
75
|
+
* hidden. As a result, the `callback` function might be called multiple times
|
|
76
|
+
* during the same page load._
|
|
77
|
+
*/
|
|
78
|
+
export const onINP = (
|
|
79
|
+
onReport: (metric: INPMetricWithAttribution) => void,
|
|
80
|
+
opts: INPAttributionReportOpts = {},
|
|
81
|
+
) => {
|
|
82
|
+
// Clone the opts object to ensure it's unique, so we can initialize a
|
|
83
|
+
// single instance of the `InteractionManager` class that's shared only with
|
|
84
|
+
// this function invocation and the `unattributedOnINP()` invocation below
|
|
85
|
+
// (which is passed the same `opts` object).
|
|
86
|
+
opts = Object.assign({}, opts);
|
|
87
|
+
|
|
88
|
+
const interactionManager = initUnique(opts, InteractionManager);
|
|
89
|
+
|
|
90
|
+
// A list of LoAF entries that have been dispatched and could potentially
|
|
91
|
+
// intersect with the INP candidate interaction. Note that periodically this
|
|
92
|
+
// list is cleaned up and entries that are known to not match INP are removed.
|
|
93
|
+
let pendingLoAFs: PerformanceLongAnimationFrameTiming[] = [];
|
|
94
|
+
|
|
95
|
+
// An array of groups of all the event timing entries that occurred within a
|
|
96
|
+
// particular frame. Note that periodically this array is cleaned up and entries
|
|
97
|
+
// that are known to not match INP are removed.
|
|
98
|
+
let pendingEntriesGroups: pendingEntriesGroup[] = [];
|
|
99
|
+
|
|
100
|
+
// The `processingEnd` time of most recently-processed event, chronologically.
|
|
101
|
+
let latestProcessingEnd: number = 0;
|
|
102
|
+
|
|
103
|
+
// A WeakMap to look up the event-timing-entries group of a given entry.
|
|
104
|
+
// Note that this only maps from "important" entries: either the first input or
|
|
105
|
+
// those with an `interactionId`.
|
|
106
|
+
const entryToEntriesGroupMap: WeakMap<
|
|
107
|
+
PerformanceEventTiming,
|
|
108
|
+
pendingEntriesGroup
|
|
109
|
+
> = new WeakMap();
|
|
110
|
+
|
|
111
|
+
// A mapping of interactionIds to the target Node.
|
|
112
|
+
const interactionTargetMap: WeakMap<Interaction, string> = new WeakMap();
|
|
113
|
+
|
|
114
|
+
// A boolean flag indicating whether or not a cleanup task has been queued.
|
|
115
|
+
let cleanupPending = false;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Adds new LoAF entries to the `pendingLoAFs` list.
|
|
119
|
+
*/
|
|
120
|
+
const handleLoAFEntries = (
|
|
121
|
+
entries: PerformanceLongAnimationFrameTiming[],
|
|
122
|
+
) => {
|
|
123
|
+
pendingLoAFs = pendingLoAFs.concat(entries);
|
|
124
|
+
queueCleanup();
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const saveInteractionTarget = (interaction: Interaction) => {
|
|
128
|
+
if (!interactionTargetMap.get(interaction)) {
|
|
129
|
+
const node = interaction.entries[0].target;
|
|
130
|
+
if (node) {
|
|
131
|
+
const customTarget = opts.generateTarget?.(node) ?? getSelector(node);
|
|
132
|
+
interactionTargetMap.set(interaction, customTarget);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Groups entries that were presented within the same animation frame by
|
|
139
|
+
* a common `renderTime`. This function works by referencing
|
|
140
|
+
* `pendingEntriesGroups` and using an existing render time if one is found
|
|
141
|
+
* (otherwise creating a new one). This function also adds all interaction
|
|
142
|
+
* entries to an `entryToRenderTimeMap` WeakMap so that the "grouped" entries
|
|
143
|
+
* can be looked up later.
|
|
144
|
+
*/
|
|
145
|
+
const groupEntriesByRenderTime = (entry: PerformanceEventTiming) => {
|
|
146
|
+
const renderTime = entry.startTime + entry.duration;
|
|
147
|
+
let group;
|
|
148
|
+
|
|
149
|
+
latestProcessingEnd = Math.max(latestProcessingEnd, entry.processingEnd);
|
|
150
|
+
|
|
151
|
+
// Iterate over all previous render times in reverse order to find a match.
|
|
152
|
+
// Go in reverse since the most likely match will be at the end.
|
|
153
|
+
for (let i = pendingEntriesGroups.length - 1; i >= 0; i--) {
|
|
154
|
+
const potentialGroup = pendingEntriesGroups[i];
|
|
155
|
+
|
|
156
|
+
// If a group's render time is within 8ms of the entry's render time,
|
|
157
|
+
// assume they were part of the same frame and add it to the group.
|
|
158
|
+
if (Math.abs(renderTime - potentialGroup.renderTime) <= 8) {
|
|
159
|
+
group = potentialGroup;
|
|
160
|
+
group.startTime = Math.min(entry.startTime, group.startTime);
|
|
161
|
+
group.processingStart = Math.min(
|
|
162
|
+
entry.processingStart,
|
|
163
|
+
group.processingStart,
|
|
164
|
+
);
|
|
165
|
+
group.processingEnd = Math.max(
|
|
166
|
+
entry.processingEnd,
|
|
167
|
+
group.processingEnd,
|
|
168
|
+
);
|
|
169
|
+
group.entries.push(entry);
|
|
170
|
+
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
54
174
|
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
175
|
+
// If there was no matching group, assume this is a new frame.
|
|
176
|
+
if (!group) {
|
|
177
|
+
group = {
|
|
178
|
+
startTime: entry.startTime,
|
|
179
|
+
processingStart: entry.processingStart,
|
|
180
|
+
processingEnd: entry.processingEnd,
|
|
181
|
+
renderTime,
|
|
182
|
+
entries: [entry],
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
pendingEntriesGroups.push(group);
|
|
186
|
+
}
|
|
59
187
|
|
|
60
|
-
//
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
188
|
+
// Store the grouped render time for this entry for reference later.
|
|
189
|
+
if (entry.interactionId || entry.entryType === 'first-input') {
|
|
190
|
+
entryToEntriesGroupMap.set(entry, group);
|
|
191
|
+
}
|
|
64
192
|
|
|
65
|
-
|
|
66
|
-
|
|
193
|
+
queueCleanup();
|
|
194
|
+
};
|
|
67
195
|
|
|
68
|
-
|
|
69
|
-
//
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
196
|
+
const queueCleanup = () => {
|
|
197
|
+
// Queue cleanup of entries that are not part of any INP candidates.
|
|
198
|
+
if (!cleanupPending) {
|
|
199
|
+
whenIdleOrHidden(cleanupEntries);
|
|
200
|
+
cleanupPending = true;
|
|
201
|
+
}
|
|
202
|
+
};
|
|
75
203
|
|
|
76
|
-
|
|
77
|
-
|
|
204
|
+
const cleanupEntries = () => {
|
|
205
|
+
// Keep all render times that are part of a pending INP candidate or
|
|
206
|
+
// that occurred within the 50 most recently-dispatched groups of events.
|
|
207
|
+
const longestInteractionGroups =
|
|
208
|
+
interactionManager._longestInteractionList.map((i) => {
|
|
209
|
+
return entryToEntriesGroupMap.get(i.entries[0]);
|
|
210
|
+
});
|
|
211
|
+
const minIndex = pendingEntriesGroups.length - MAX_PREVIOUS_FRAMES;
|
|
212
|
+
pendingEntriesGroups = pendingEntriesGroups.filter((group, index) => {
|
|
213
|
+
if (index >= minIndex) return true;
|
|
214
|
+
return longestInteractionGroups.includes(group);
|
|
215
|
+
});
|
|
78
216
|
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
|
|
217
|
+
// Keep all pending LoAF entries that either:
|
|
218
|
+
// 1) intersect with entries in the newly cleaned up `pendingEntriesGroups`
|
|
219
|
+
// 2) occur after the most recently-processed event entry (for up to MAX_PREVIOUS_FRAMES)
|
|
220
|
+
const loafsToKeep: Set<PerformanceLongAnimationFrameTiming> = new Set();
|
|
221
|
+
for (const group of pendingEntriesGroups) {
|
|
222
|
+
const loafs = getIntersectingLoAFs(group.startTime, group.processingEnd);
|
|
223
|
+
for (const loaf of loafs) {
|
|
224
|
+
loafsToKeep.add(loaf);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const prevFrameIndexCutoff = pendingLoAFs.length - 1 - MAX_PREVIOUS_FRAMES;
|
|
228
|
+
// Filter `pendingLoAFs` to preserve LoAF order.
|
|
229
|
+
pendingLoAFs = pendingLoAFs.filter((loaf, index) => {
|
|
230
|
+
if (
|
|
231
|
+
loaf.startTime > latestProcessingEnd &&
|
|
232
|
+
index > prevFrameIndexCutoff
|
|
233
|
+
) {
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
83
236
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
*/
|
|
87
|
-
const handleLoAFEntries = (entries: PerformanceLongAnimationFrameTiming[]) => {
|
|
88
|
-
pendingLoAFs = pendingLoAFs.concat(entries);
|
|
89
|
-
queueCleanup();
|
|
90
|
-
};
|
|
237
|
+
return loafsToKeep.has(loaf);
|
|
238
|
+
});
|
|
91
239
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
entry
|
|
97
|
-
entry.target &&
|
|
98
|
-
!interactionTargetMap.has(entry.interactionId)
|
|
240
|
+
cleanupPending = false;
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
async function handleOnEachInteractionCallback(
|
|
244
|
+
entry: PerformanceEventTiming,
|
|
99
245
|
) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
246
|
+
if (!opts.onEachInteraction) {
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
103
249
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
* entries to an `entryToRenderTimeMap` WeakMap so that the "grouped" entries
|
|
110
|
-
* can be looked up later.
|
|
111
|
-
*/
|
|
112
|
-
const groupEntriesByRenderTime = (entry: PerformanceEventTiming) => {
|
|
113
|
-
const renderTime = entry.startTime + entry.duration;
|
|
114
|
-
let group;
|
|
115
|
-
|
|
116
|
-
latestProcessingEnd = Math.max(latestProcessingEnd, entry.processingEnd);
|
|
117
|
-
|
|
118
|
-
// Iterate over all previous render times in reverse order to find a match.
|
|
119
|
-
// Go in reverse since the most likely match will be at the end.
|
|
120
|
-
for (let i = pendingEntriesGroups.length - 1; i >= 0; i--) {
|
|
121
|
-
const potentialGroup = pendingEntriesGroups[i];
|
|
122
|
-
|
|
123
|
-
// If a group's render time is within 8ms of the entry's render time,
|
|
124
|
-
// assume they were part of the same frame and add it to the group.
|
|
125
|
-
if (Math.abs(renderTime - potentialGroup.renderTime) <= 8) {
|
|
126
|
-
group = potentialGroup;
|
|
127
|
-
group.startTime = Math.min(entry.startTime, group.startTime);
|
|
128
|
-
group.processingStart = Math.min(
|
|
129
|
-
entry.processingStart,
|
|
130
|
-
group.processingStart,
|
|
131
|
-
);
|
|
132
|
-
group.processingEnd = Math.max(entry.processingEnd, group.processingEnd);
|
|
133
|
-
group.entries.push(entry);
|
|
134
|
-
|
|
135
|
-
break;
|
|
250
|
+
// Wait a microtask so this "pre" processing callback actually
|
|
251
|
+
// becomes a "post" processing callback.
|
|
252
|
+
void (await Promise.resolve());
|
|
253
|
+
if (!entry.interactionId) {
|
|
254
|
+
return;
|
|
136
255
|
}
|
|
137
|
-
}
|
|
138
256
|
|
|
139
|
-
|
|
140
|
-
if (!group) {
|
|
141
|
-
group = {
|
|
142
|
-
startTime: entry.startTime,
|
|
143
|
-
processingStart: entry.processingStart,
|
|
144
|
-
processingEnd: entry.processingEnd,
|
|
145
|
-
renderTime,
|
|
257
|
+
const interaction = attributeINP({
|
|
146
258
|
entries: [entry],
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
259
|
+
// The only value we really need for `attributeINP` is `entries`
|
|
260
|
+
// Everything else is included to fill out the type.
|
|
261
|
+
name: 'INP',
|
|
262
|
+
rating: 'good',
|
|
263
|
+
value: entry.duration,
|
|
264
|
+
delta: entry.duration,
|
|
265
|
+
navigationType: 'navigate',
|
|
266
|
+
id: 'N/A',
|
|
267
|
+
});
|
|
268
|
+
opts.onEachInteraction(interaction);
|
|
150
269
|
}
|
|
151
270
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
271
|
+
interactionManager._onBeforeProcessingEntry = (
|
|
272
|
+
entry: PerformanceEventTiming,
|
|
273
|
+
) => {
|
|
274
|
+
void handleOnEachInteractionCallback(entry);
|
|
275
|
+
groupEntriesByRenderTime(entry);
|
|
276
|
+
};
|
|
277
|
+
interactionManager._onAfterProcessingINPCandidate = saveInteractionTarget;
|
|
156
278
|
|
|
157
|
-
|
|
158
|
-
|
|
279
|
+
const getIntersectingLoAFs = (
|
|
280
|
+
start: DOMHighResTimeStamp,
|
|
281
|
+
end: DOMHighResTimeStamp,
|
|
282
|
+
) => {
|
|
283
|
+
const intersectingLoAFs: PerformanceLongAnimationFrameTiming[] = [];
|
|
159
284
|
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
285
|
+
for (const loaf of pendingLoAFs) {
|
|
286
|
+
// If the LoAF ends before the given start time, ignore it.
|
|
287
|
+
if (loaf.startTime + loaf.duration < start) continue;
|
|
288
|
+
|
|
289
|
+
// If the LoAF starts after the given end time, ignore it and all
|
|
290
|
+
// subsequent pending LoAFs (because they're in time order).
|
|
291
|
+
if (loaf.startTime > end) break;
|
|
166
292
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
293
|
+
// Still here? If so this LoAF intersects with the interaction.
|
|
294
|
+
intersectingLoAFs.push(loaf);
|
|
295
|
+
}
|
|
296
|
+
return intersectingLoAFs;
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
const attributeLoAFDetails = (attribution: INPAttribution) => {
|
|
300
|
+
// If there is no LoAF data then nothing further to attribute
|
|
301
|
+
if (!attribution.longAnimationFrameEntries?.length) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const interactionTime = attribution.interactionTime;
|
|
306
|
+
const inputDelay = attribution.inputDelay;
|
|
307
|
+
const processingDuration = attribution.processingDuration;
|
|
308
|
+
|
|
309
|
+
// Stats across all LoAF entries and scripts.
|
|
310
|
+
let totalScriptDuration = 0;
|
|
311
|
+
let totalStyleAndLayoutDuration = 0;
|
|
312
|
+
let totalPaintDuration = 0;
|
|
313
|
+
let longestScriptDuration = 0;
|
|
314
|
+
let longestScriptEntry: PerformanceScriptTiming | undefined;
|
|
315
|
+
let longestScriptSubpart: INPLongestScriptSummary['subpart'] | undefined;
|
|
316
|
+
|
|
317
|
+
for (const loafEntry of attribution.longAnimationFrameEntries) {
|
|
318
|
+
totalStyleAndLayoutDuration =
|
|
319
|
+
totalStyleAndLayoutDuration +
|
|
320
|
+
loafEntry.startTime +
|
|
321
|
+
loafEntry.duration -
|
|
322
|
+
loafEntry.styleAndLayoutStart;
|
|
323
|
+
|
|
324
|
+
for (const script of loafEntry.scripts) {
|
|
325
|
+
const scriptEndTime = script.startTime + script.duration;
|
|
326
|
+
if (scriptEndTime < interactionTime) {
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
const intersectingScriptDuration =
|
|
330
|
+
scriptEndTime - Math.max(interactionTime, script.startTime);
|
|
331
|
+
// Since forcedStyleAndLayoutDuration doesn't provide timestamps, we
|
|
332
|
+
// apportion the total based on the intersectingScriptDuration. Not
|
|
333
|
+
// correct depending on when it occurred, but the best we can do.
|
|
334
|
+
const intersectingForceStyleAndLayoutDuration = script.duration
|
|
335
|
+
? (intersectingScriptDuration / script.duration) *
|
|
336
|
+
script.forcedStyleAndLayoutDuration
|
|
337
|
+
: 0;
|
|
338
|
+
// For scripts we exclude forcedStyleAndLayout (same as DevTools does
|
|
339
|
+
// in its summary totals) and instead include that in
|
|
340
|
+
// totalStyleAndLayoutDuration
|
|
341
|
+
totalScriptDuration +=
|
|
342
|
+
intersectingScriptDuration - intersectingForceStyleAndLayoutDuration;
|
|
343
|
+
totalStyleAndLayoutDuration += intersectingForceStyleAndLayoutDuration;
|
|
344
|
+
|
|
345
|
+
if (intersectingScriptDuration > longestScriptDuration) {
|
|
346
|
+
// Set the subpart this occurred in.
|
|
347
|
+
longestScriptSubpart =
|
|
348
|
+
script.startTime < interactionTime + inputDelay
|
|
349
|
+
? 'input-delay'
|
|
350
|
+
: script.startTime >=
|
|
351
|
+
interactionTime + inputDelay + processingDuration
|
|
352
|
+
? 'presentation-delay'
|
|
353
|
+
: 'processing-duration';
|
|
354
|
+
|
|
355
|
+
longestScriptEntry = script;
|
|
356
|
+
longestScriptDuration = intersectingScriptDuration;
|
|
357
|
+
}
|
|
174
358
|
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
359
|
+
}
|
|
177
360
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
return longestInteractionGroups.includes(group);
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
// Keep all pending LoAF entries that either:
|
|
190
|
-
// 1) intersect with entries in the newly cleaned up `pendingEntriesGroups`
|
|
191
|
-
// 2) occur after the most recently-processed event entry (for up to MAX_PREVIOUS_FRAMES)
|
|
192
|
-
const loafsToKeep: Set<PerformanceLongAnimationFrameTiming> = new Set();
|
|
193
|
-
for (let i = 0; i < pendingEntriesGroups.length; i++) {
|
|
194
|
-
const group = pendingEntriesGroups[i];
|
|
195
|
-
getIntersectingLoAFs(group.startTime, group.processingEnd).forEach(
|
|
196
|
-
(loaf) => {
|
|
197
|
-
loafsToKeep.add(loaf);
|
|
198
|
-
},
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
const prevFrameIndexCutoff = pendingLoAFs.length - 1 - MAX_PREVIOUS_FRAMES;
|
|
202
|
-
// Filter `pendingLoAFs` to preserve LoAF order.
|
|
203
|
-
pendingLoAFs = pendingLoAFs.filter((loaf, index) => {
|
|
204
|
-
if (loaf.startTime > latestProcessingEnd && index > prevFrameIndexCutoff) {
|
|
205
|
-
return true;
|
|
361
|
+
// Calculate the totalPaintDuration from the last LoAF after
|
|
362
|
+
// presentationDelay starts (where available)
|
|
363
|
+
const lastLoAF = attribution.longAnimationFrameEntries.at(-1);
|
|
364
|
+
const lastLoAFEndTime = lastLoAF
|
|
365
|
+
? lastLoAF.startTime + lastLoAF.duration
|
|
366
|
+
: 0;
|
|
367
|
+
if (lastLoAFEndTime >= interactionTime + inputDelay + processingDuration) {
|
|
368
|
+
totalPaintDuration = attribution.nextPaintTime - lastLoAFEndTime;
|
|
206
369
|
}
|
|
207
370
|
|
|
208
|
-
|
|
209
|
-
|
|
371
|
+
if (longestScriptEntry && longestScriptSubpart) {
|
|
372
|
+
attribution.longestScript = {
|
|
373
|
+
entry: longestScriptEntry,
|
|
374
|
+
subpart: longestScriptSubpart,
|
|
375
|
+
intersectingDuration: longestScriptDuration,
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
attribution.totalScriptDuration = totalScriptDuration;
|
|
379
|
+
attribution.totalStyleAndLayoutDuration = totalStyleAndLayoutDuration;
|
|
380
|
+
attribution.totalPaintDuration = totalPaintDuration;
|
|
381
|
+
attribution.totalUnattributedDuration =
|
|
382
|
+
attribution.nextPaintTime -
|
|
383
|
+
interactionTime -
|
|
384
|
+
totalScriptDuration -
|
|
385
|
+
totalStyleAndLayoutDuration -
|
|
386
|
+
totalPaintDuration;
|
|
387
|
+
};
|
|
210
388
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
389
|
+
const attributeINP = (metric: INPMetric): INPMetricWithAttribution => {
|
|
390
|
+
const firstEntry = metric.entries[0];
|
|
391
|
+
const group = entryToEntriesGroupMap.get(firstEntry)!;
|
|
214
392
|
|
|
215
|
-
|
|
216
|
-
saveInteractionTarget,
|
|
217
|
-
groupEntriesByRenderTime,
|
|
218
|
-
);
|
|
393
|
+
const processingStart = firstEntry.processingStart;
|
|
219
394
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
395
|
+
// Due to the fact that durations can be rounded down to the nearest 8ms,
|
|
396
|
+
// we have to clamp `nextPaintTime` so it doesn't appear to occur before
|
|
397
|
+
// processing starts. Note: we can't use `processingEnd` since processing
|
|
398
|
+
// can extend beyond the event duration in some cases (see next comment).
|
|
399
|
+
const nextPaintTime = Math.max(
|
|
400
|
+
firstEntry.startTime + firstEntry.duration,
|
|
401
|
+
processingStart,
|
|
402
|
+
);
|
|
225
403
|
|
|
226
|
-
|
|
227
|
-
//
|
|
228
|
-
|
|
404
|
+
// For the purposes of attribution, clamp `processingEnd` to `nextPaintTime`,
|
|
405
|
+
// so processing is never reported as taking longer than INP (which can
|
|
406
|
+
// happen via the web APIs in the case of sync modals, e.g. `alert()`).
|
|
407
|
+
// See: https://github.com/GoogleChrome/web-vitals/issues/492
|
|
408
|
+
const processingEnd = Math.min(group.processingEnd, nextPaintTime);
|
|
229
409
|
|
|
230
|
-
//
|
|
231
|
-
|
|
232
|
-
|
|
410
|
+
// Sort the entries in processing time order.
|
|
411
|
+
const processedEventEntries = group.entries.sort((a, b) => {
|
|
412
|
+
return a.processingStart - b.processingStart;
|
|
413
|
+
});
|
|
233
414
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
415
|
+
const longAnimationFrameEntries: PerformanceLongAnimationFrameTiming[] =
|
|
416
|
+
getIntersectingLoAFs(firstEntry.startTime, processingEnd);
|
|
417
|
+
|
|
418
|
+
const interaction = interactionManager._longestInteractionMap.get(
|
|
419
|
+
firstEntry.interactionId,
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
const attribution: INPAttribution = {
|
|
423
|
+
// TS flags the next line because `interactionTargetMap.get()` might
|
|
424
|
+
// return `undefined`, but we ignore this assuming the user knows what
|
|
425
|
+
// they are doing.
|
|
426
|
+
interactionTarget: interactionTargetMap.get(interaction!)!,
|
|
427
|
+
interactionType: firstEntry.name.startsWith('key')
|
|
428
|
+
? 'keyboard'
|
|
429
|
+
: 'pointer',
|
|
430
|
+
interactionTime: firstEntry.startTime,
|
|
431
|
+
nextPaintTime: nextPaintTime,
|
|
432
|
+
processedEventEntries: processedEventEntries,
|
|
433
|
+
longAnimationFrameEntries: longAnimationFrameEntries,
|
|
434
|
+
inputDelay: processingStart - firstEntry.startTime,
|
|
435
|
+
processingDuration: processingEnd - processingStart,
|
|
436
|
+
presentationDelay: nextPaintTime - processingEnd,
|
|
437
|
+
loadState: getLoadState(firstEntry.startTime),
|
|
438
|
+
longestScript: undefined,
|
|
439
|
+
totalScriptDuration: undefined,
|
|
440
|
+
totalStyleAndLayoutDuration: undefined,
|
|
441
|
+
totalPaintDuration: undefined,
|
|
442
|
+
totalUnattributedDuration: undefined,
|
|
443
|
+
};
|
|
239
444
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
const processedEventEntries = group.entries.sort((a, b) => {
|
|
249
|
-
return a.processingStart - b.processingStart;
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
const longAnimationFrameEntries: PerformanceLongAnimationFrameTiming[] =
|
|
253
|
-
getIntersectingLoAFs(firstEntry.startTime, processingEnd);
|
|
254
|
-
|
|
255
|
-
// The first interaction entry may not have a target defined, so use the
|
|
256
|
-
// first one found in the entry list.
|
|
257
|
-
// TODO: when the following bug is fixed just use `firstInteractionEntry`.
|
|
258
|
-
// https://bugs.chromium.org/p/chromium/issues/detail?id=1367329
|
|
259
|
-
// As a fallback, also check the interactionTargetMap (to account for
|
|
260
|
-
// cases where the element is removed from the DOM before reporting happens).
|
|
261
|
-
const firstEntryWithTarget = metric.entries.find((entry) => entry.target);
|
|
262
|
-
const interactionTargetElement =
|
|
263
|
-
(firstEntryWithTarget && firstEntryWithTarget.target) ||
|
|
264
|
-
interactionTargetMap.get(firstEntry.interactionId);
|
|
265
|
-
|
|
266
|
-
// Since entry durations are rounded to the nearest 8ms, we need to clamp
|
|
267
|
-
// the `nextPaintTime` value to be higher than the `processingEnd` or
|
|
268
|
-
// end time of any LoAF entry.
|
|
269
|
-
const nextPaintTimeCandidates = [
|
|
270
|
-
firstEntry.startTime + firstEntry.duration,
|
|
271
|
-
processingEnd,
|
|
272
|
-
].concat(
|
|
273
|
-
longAnimationFrameEntries.map((loaf) => loaf.startTime + loaf.duration),
|
|
274
|
-
);
|
|
275
|
-
|
|
276
|
-
const nextPaintTime = Math.max.apply(Math, nextPaintTimeCandidates);
|
|
277
|
-
|
|
278
|
-
const attribution: INPAttribution = {
|
|
279
|
-
interactionTarget: getSelector(interactionTargetElement),
|
|
280
|
-
interactionTargetElement: interactionTargetElement,
|
|
281
|
-
interactionType: firstEntry.name.startsWith('key') ? 'keyboard' : 'pointer',
|
|
282
|
-
interactionTime: firstEntry.startTime,
|
|
283
|
-
nextPaintTime: nextPaintTime,
|
|
284
|
-
processedEventEntries: processedEventEntries,
|
|
285
|
-
longAnimationFrameEntries: longAnimationFrameEntries,
|
|
286
|
-
inputDelay: processingStart - firstEntry.startTime,
|
|
287
|
-
processingDuration: processingEnd - processingStart,
|
|
288
|
-
presentationDelay: Math.max(nextPaintTime - processingEnd, 0),
|
|
289
|
-
loadState: getLoadState(firstEntry.startTime),
|
|
445
|
+
attributeLoAFDetails(attribution);
|
|
446
|
+
|
|
447
|
+
// Use `Object.assign()` to ensure the original metric object is returned.
|
|
448
|
+
const metricWithAttribution: INPMetricWithAttribution = Object.assign(
|
|
449
|
+
metric,
|
|
450
|
+
{attribution},
|
|
451
|
+
);
|
|
452
|
+
return metricWithAttribution;
|
|
290
453
|
};
|
|
291
454
|
|
|
292
|
-
//
|
|
293
|
-
|
|
294
|
-
metric,
|
|
295
|
-
{attribution},
|
|
296
|
-
);
|
|
297
|
-
return metricWithAttribution;
|
|
298
|
-
};
|
|
455
|
+
// Start observing LoAF entries for attribution.
|
|
456
|
+
observe('long-animation-frame', handleLoAFEntries);
|
|
299
457
|
|
|
300
|
-
/**
|
|
301
|
-
* Calculates the [INP](https://web.dev/articles/inp) value for the current
|
|
302
|
-
* page and calls the `callback` function once the value is ready, along with
|
|
303
|
-
* the `event` performance entries reported for that interaction. The reported
|
|
304
|
-
* value is a `DOMHighResTimeStamp`.
|
|
305
|
-
*
|
|
306
|
-
* A custom `durationThreshold` configuration option can optionally be passed to
|
|
307
|
-
* control what `event-timing` entries are considered for INP reporting. The
|
|
308
|
-
* default threshold is `40`, which means INP scores of less than 40 are
|
|
309
|
-
* reported as 0. Note that this will not affect your 75th percentile INP value
|
|
310
|
-
* unless that value is also less than 40 (well below the recommended
|
|
311
|
-
* [good](https://web.dev/articles/inp#what_is_a_good_inp_score) threshold).
|
|
312
|
-
*
|
|
313
|
-
* If the `reportAllChanges` configuration option is set to `true`, the
|
|
314
|
-
* `callback` function will be called as soon as the value is initially
|
|
315
|
-
* determined as well as any time the value changes throughout the page
|
|
316
|
-
* lifespan.
|
|
317
|
-
*
|
|
318
|
-
* _**Important:** INP should be continually monitored for changes throughout
|
|
319
|
-
* the entire lifespan of a page—including if the user returns to the page after
|
|
320
|
-
* it's been hidden/backgrounded. However, since browsers often [will not fire
|
|
321
|
-
* additional callbacks once the user has backgrounded a
|
|
322
|
-
* page](https://developer.chrome.com/blog/page-lifecycle-api/#advice-hidden),
|
|
323
|
-
* `callback` is always called when the page's visibility state changes to
|
|
324
|
-
* hidden. As a result, the `callback` function might be called multiple times
|
|
325
|
-
* during the same page load._
|
|
326
|
-
*/
|
|
327
|
-
export const onINP = (
|
|
328
|
-
onReport: (metric: INPMetricWithAttribution) => void,
|
|
329
|
-
opts?: ReportOpts,
|
|
330
|
-
) => {
|
|
331
|
-
if (!loafObserver) {
|
|
332
|
-
loafObserver = observe('long-animation-frame', handleLoAFEntries);
|
|
333
|
-
}
|
|
334
458
|
unattributedOnINP((metric: INPMetric) => {
|
|
335
459
|
const metricWithAttribution = attributeINP(metric);
|
|
336
460
|
onReport(metricWithAttribution);
|