chrome-devtools-frontend 1.0.1526203 → 1.0.1528866
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/i18n/i18nImpl.ts +5 -0
- package/front_end/core/protocol_client/protocol_client.ts +1 -1
- package/front_end/core/root/Runtime.ts +28 -4
- package/front_end/core/sdk/CSSMatchedStyles.ts +50 -7
- package/front_end/core/sdk/CSSRule.ts +35 -6
- package/front_end/core/sdk/ChildTargetManager.ts +2 -0
- 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 +214 -31
- 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 +37 -11
- package/front_end/core/sdk/SourceMapManager.ts +13 -2
- package/front_end/core/sdk/SourceMapScopesInfo.ts +17 -0
- 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 +20 -25
- package/front_end/generated/InspectorBackendCommands.js +4 -3
- package/front_end/generated/protocol-mapping.d.ts +3 -1
- package/front_end/generated/protocol-proxy-api.d.ts +3 -1
- package/front_end/generated/protocol.ts +17 -3
- package/front_end/models/ai_assistance/BuiltInAi.ts +111 -0
- 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 +23 -27
- package/front_end/models/live-metrics/web-vitals-injected/web-vitals-injected.ts +31 -29
- package/front_end/models/persistence/EditFileSystemView.ts +1 -0
- 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/panels/console/ConsoleInsightTeaser.ts +106 -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 +27 -0
- package/front_end/panels/{explain → console}/PromptBuilder.ts +12 -7
- package/front_end/panels/console/console.ts +6 -0
- package/front_end/panels/console/consoleInsightTeaser.css +55 -0
- package/front_end/panels/coverage/CoverageListView.ts +141 -277
- package/front_end/panels/coverage/CoverageView.ts +330 -324
- 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 +1 -2
- package/front_end/panels/explain/components/ConsoleInsight.ts +14 -12
- 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 +12 -19
- package/front_end/panels/linear_memory_inspector/components/LinearMemoryInspector.ts +27 -43
- 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 +111 -85
- 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 +2 -1
- 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/panels/settings/WorkspaceSettingsTab.ts +2 -0
- package/front_end/panels/settings/emulation/components/UserAgentClientHintsForm.ts +2 -2
- 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/panels/sources/UISourceCodeFrame.ts +17 -2
- 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/web_audio/WebAudioView.ts +1 -0
- package/front_end/third_party/chromium/README.chromium +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/buttons/Button.ts +1 -1
- 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/EmptyWidget.ts +11 -1
- package/front_end/ui/legacy/InspectorView.ts +2 -0
- 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/Toolbar.ts +25 -4
- package/front_end/ui/legacy/UIUtils.ts +28 -13
- package/front_end/ui/legacy/ViewManager.ts +1 -0
- package/front_end/ui/legacy/Widget.ts +5 -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/data_grid/DataGridElement.ts +1 -1
- 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 +9 -8
- package/front_end/ui/visual_logging/KnownContextValues.ts +17 -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
|
@@ -16,81 +16,16 @@
|
|
|
16
16
|
|
|
17
17
|
import {getNavigationEntry} from '../lib/getNavigationEntry.js';
|
|
18
18
|
import {getSelector} from '../lib/getSelector.js';
|
|
19
|
+
import {initUnique} from '../lib/initUnique.js';
|
|
20
|
+
import {LCPEntryManager} from '../lib/LCPEntryManager.js';
|
|
19
21
|
import {onLCP as unattributedOnLCP} from '../onLCP.js';
|
|
20
22
|
import {
|
|
21
23
|
LCPAttribution,
|
|
22
24
|
LCPMetric,
|
|
23
25
|
LCPMetricWithAttribution,
|
|
24
|
-
|
|
26
|
+
AttributionReportOpts,
|
|
25
27
|
} from '../types.js';
|
|
26
28
|
|
|
27
|
-
const attributeLCP = (metric: LCPMetric): LCPMetricWithAttribution => {
|
|
28
|
-
// Use a default object if no other attribution has been set.
|
|
29
|
-
let attribution: LCPAttribution = {
|
|
30
|
-
timeToFirstByte: 0,
|
|
31
|
-
resourceLoadDelay: 0,
|
|
32
|
-
resourceLoadDuration: 0,
|
|
33
|
-
elementRenderDelay: metric.value,
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
if (metric.entries.length) {
|
|
37
|
-
const navigationEntry = getNavigationEntry();
|
|
38
|
-
if (navigationEntry) {
|
|
39
|
-
const activationStart = navigationEntry.activationStart || 0;
|
|
40
|
-
const lcpEntry = metric.entries[metric.entries.length - 1];
|
|
41
|
-
const lcpResourceEntry =
|
|
42
|
-
lcpEntry.url &&
|
|
43
|
-
performance
|
|
44
|
-
.getEntriesByType('resource')
|
|
45
|
-
.filter((e) => e.name === lcpEntry.url)[0];
|
|
46
|
-
|
|
47
|
-
const ttfb = Math.max(0, navigationEntry.responseStart - activationStart);
|
|
48
|
-
|
|
49
|
-
const lcpRequestStart = Math.max(
|
|
50
|
-
ttfb,
|
|
51
|
-
// Prefer `requestStart` (if TOA is set), otherwise use `startTime`.
|
|
52
|
-
lcpResourceEntry
|
|
53
|
-
? (lcpResourceEntry.requestStart || lcpResourceEntry.startTime) -
|
|
54
|
-
activationStart
|
|
55
|
-
: 0,
|
|
56
|
-
);
|
|
57
|
-
const lcpResponseEnd = Math.max(
|
|
58
|
-
lcpRequestStart,
|
|
59
|
-
lcpResourceEntry ? lcpResourceEntry.responseEnd - activationStart : 0,
|
|
60
|
-
);
|
|
61
|
-
const lcpRenderTime = Math.max(
|
|
62
|
-
lcpResponseEnd,
|
|
63
|
-
lcpEntry.startTime - activationStart,
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
attribution = {
|
|
67
|
-
element: getSelector(lcpEntry.element),
|
|
68
|
-
timeToFirstByte: ttfb,
|
|
69
|
-
resourceLoadDelay: lcpRequestStart - ttfb,
|
|
70
|
-
resourceLoadDuration: lcpResponseEnd - lcpRequestStart,
|
|
71
|
-
elementRenderDelay: lcpRenderTime - lcpResponseEnd,
|
|
72
|
-
navigationEntry,
|
|
73
|
-
lcpEntry,
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
// Only attribution the URL and resource entry if they exist.
|
|
77
|
-
if (lcpEntry.url) {
|
|
78
|
-
attribution.url = lcpEntry.url;
|
|
79
|
-
}
|
|
80
|
-
if (lcpResourceEntry) {
|
|
81
|
-
attribution.lcpResourceEntry = lcpResourceEntry;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Use Object.assign to set property to keep tsc happy.
|
|
87
|
-
const metricWithAttribution: LCPMetricWithAttribution = Object.assign(
|
|
88
|
-
metric,
|
|
89
|
-
{attribution},
|
|
90
|
-
);
|
|
91
|
-
return metricWithAttribution;
|
|
92
|
-
};
|
|
93
|
-
|
|
94
29
|
/**
|
|
95
30
|
* Calculates the [LCP](https://web.dev/articles/lcp) value for the current page and
|
|
96
31
|
* calls the `callback` function once the value is ready (along with the
|
|
@@ -104,8 +39,100 @@ const attributeLCP = (metric: LCPMetric): LCPMetricWithAttribution => {
|
|
|
104
39
|
*/
|
|
105
40
|
export const onLCP = (
|
|
106
41
|
onReport: (metric: LCPMetricWithAttribution) => void,
|
|
107
|
-
opts
|
|
42
|
+
opts: AttributionReportOpts = {},
|
|
108
43
|
) => {
|
|
44
|
+
// Clone the opts object to ensure it's unique, so we can initialize a
|
|
45
|
+
// single instance of the `LCPEntryManager` class that's shared only with
|
|
46
|
+
// this function invocation and the `unattributedOnLCP()` invocation below
|
|
47
|
+
// (which is passed the same `opts` object).
|
|
48
|
+
opts = Object.assign({}, opts);
|
|
49
|
+
|
|
50
|
+
const lcpEntryManager = initUnique(opts, LCPEntryManager);
|
|
51
|
+
const lcpTargetMap: WeakMap<LargestContentfulPaint, string> = new WeakMap();
|
|
52
|
+
|
|
53
|
+
lcpEntryManager._onBeforeProcessingEntry = (
|
|
54
|
+
entry: LargestContentfulPaint,
|
|
55
|
+
) => {
|
|
56
|
+
const node = entry.element;
|
|
57
|
+
if (node) {
|
|
58
|
+
const customTarget = opts.generateTarget?.(node) ?? getSelector(node);
|
|
59
|
+
lcpTargetMap.set(entry, customTarget);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const attributeLCP = (metric: LCPMetric): LCPMetricWithAttribution => {
|
|
64
|
+
// Use a default object if no other attribution has been set.
|
|
65
|
+
let attribution: LCPAttribution = {
|
|
66
|
+
timeToFirstByte: 0,
|
|
67
|
+
resourceLoadDelay: 0,
|
|
68
|
+
resourceLoadDuration: 0,
|
|
69
|
+
elementRenderDelay: metric.value,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
if (metric.entries.length) {
|
|
73
|
+
const navigationEntry = getNavigationEntry();
|
|
74
|
+
if (navigationEntry) {
|
|
75
|
+
const activationStart = navigationEntry.activationStart || 0;
|
|
76
|
+
// The `metric.entries.length` check ensures there will be an entry.
|
|
77
|
+
const lcpEntry = metric.entries.at(-1)!;
|
|
78
|
+
const lcpResourceEntry =
|
|
79
|
+
lcpEntry.url &&
|
|
80
|
+
performance
|
|
81
|
+
.getEntriesByType('resource')
|
|
82
|
+
.filter((e) => e.name === lcpEntry.url)[0];
|
|
83
|
+
|
|
84
|
+
const ttfb = Math.max(
|
|
85
|
+
0,
|
|
86
|
+
navigationEntry.responseStart - activationStart,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const lcpRequestStart = Math.max(
|
|
90
|
+
ttfb,
|
|
91
|
+
// Prefer `requestStart` (if TOA is set), otherwise use `startTime`.
|
|
92
|
+
lcpResourceEntry
|
|
93
|
+
? (lcpResourceEntry.requestStart || lcpResourceEntry.startTime) -
|
|
94
|
+
activationStart
|
|
95
|
+
: 0,
|
|
96
|
+
);
|
|
97
|
+
const lcpResponseEnd = Math.min(
|
|
98
|
+
// Cap at LCP time (videos continue downloading after LCP for example)
|
|
99
|
+
metric.value,
|
|
100
|
+
Math.max(
|
|
101
|
+
lcpRequestStart,
|
|
102
|
+
lcpResourceEntry
|
|
103
|
+
? lcpResourceEntry.responseEnd - activationStart
|
|
104
|
+
: 0,
|
|
105
|
+
),
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
attribution = {
|
|
109
|
+
target: lcpTargetMap.get(lcpEntry),
|
|
110
|
+
timeToFirstByte: ttfb,
|
|
111
|
+
resourceLoadDelay: lcpRequestStart - ttfb,
|
|
112
|
+
resourceLoadDuration: lcpResponseEnd - lcpRequestStart,
|
|
113
|
+
elementRenderDelay: metric.value - lcpResponseEnd,
|
|
114
|
+
navigationEntry,
|
|
115
|
+
lcpEntry,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Only attribute the URL and resource entry if they exist.
|
|
119
|
+
if (lcpEntry.url) {
|
|
120
|
+
attribution.url = lcpEntry.url;
|
|
121
|
+
}
|
|
122
|
+
if (lcpResourceEntry) {
|
|
123
|
+
attribution.lcpResourceEntry = lcpResourceEntry;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Use `Object.assign()` to ensure the original metric object is returned.
|
|
129
|
+
const metricWithAttribution: LCPMetricWithAttribution = Object.assign(
|
|
130
|
+
metric,
|
|
131
|
+
{attribution},
|
|
132
|
+
);
|
|
133
|
+
return metricWithAttribution;
|
|
134
|
+
};
|
|
135
|
+
|
|
109
136
|
unattributedOnLCP((metric: LCPMetric) => {
|
|
110
137
|
const metricWithAttribution = attributeLCP(metric);
|
|
111
138
|
onReport(metricWithAttribution);
|
|
@@ -18,7 +18,7 @@ import {onTTFB as unattributedOnTTFB} from '../onTTFB.js';
|
|
|
18
18
|
import {
|
|
19
19
|
TTFBMetric,
|
|
20
20
|
TTFBMetricWithAttribution,
|
|
21
|
-
|
|
21
|
+
AttributionReportOpts,
|
|
22
22
|
TTFBAttribution,
|
|
23
23
|
} from '../types.js';
|
|
24
24
|
|
|
@@ -73,7 +73,7 @@ const attributeTTFB = (metric: TTFBMetric): TTFBMetricWithAttribution => {
|
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
// Use Object.assign to
|
|
76
|
+
// Use `Object.assign()` to ensure the original metric object is returned.
|
|
77
77
|
const metricWithAttribution: TTFBMetricWithAttribution = Object.assign(
|
|
78
78
|
metric,
|
|
79
79
|
{attribution},
|
|
@@ -98,7 +98,7 @@ const attributeTTFB = (metric: TTFBMetric): TTFBMetricWithAttribution => {
|
|
|
98
98
|
*/
|
|
99
99
|
export const onTTFB = (
|
|
100
100
|
onReport: (metric: TTFBMetricWithAttribution) => void,
|
|
101
|
-
opts
|
|
101
|
+
opts: AttributionReportOpts = {},
|
|
102
102
|
) => {
|
|
103
103
|
unattributedOnTTFB((metric: TTFBMetric) => {
|
|
104
104
|
const metricWithAttribution = attributeTTFB(metric);
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 Google LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* https://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {getInteractionCount} from './polyfills/interactionCountPolyfill.js';
|
|
18
|
+
|
|
19
|
+
export interface Interaction {
|
|
20
|
+
_latency: number;
|
|
21
|
+
// While the `id` and `entries` properties are also internal and could be
|
|
22
|
+
// mangled by prefixing with an underscore, since they correspond to public
|
|
23
|
+
// symbols there is no need to mangle them as the library will compress
|
|
24
|
+
// better if we reuse the existing names.
|
|
25
|
+
id: number;
|
|
26
|
+
entries: PerformanceEventTiming[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// To prevent unnecessary memory usage on pages with lots of interactions,
|
|
30
|
+
// store at most 10 of the longest interactions to consider as INP candidates.
|
|
31
|
+
const MAX_INTERACTIONS_TO_CONSIDER = 10;
|
|
32
|
+
|
|
33
|
+
// Used to store the interaction count after a bfcache restore, since p98
|
|
34
|
+
// interaction latencies should only consider the current navigation.
|
|
35
|
+
let prevInteractionCount = 0;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Returns the interaction count since the last bfcache restore (or for the
|
|
39
|
+
* full page lifecycle if there were no bfcache restores).
|
|
40
|
+
*/
|
|
41
|
+
const getInteractionCountForNavigation = () => {
|
|
42
|
+
return getInteractionCount() - prevInteractionCount;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export class InteractionManager {
|
|
46
|
+
/**
|
|
47
|
+
* A list of longest interactions on the page (by latency) sorted so the
|
|
48
|
+
* longest one is first. The list is at most MAX_INTERACTIONS_TO_CONSIDER
|
|
49
|
+
* long.
|
|
50
|
+
*/
|
|
51
|
+
_longestInteractionList: Interaction[] = [];
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* A mapping of longest interactions by their interaction ID.
|
|
55
|
+
* This is used for faster lookup.
|
|
56
|
+
*/
|
|
57
|
+
_longestInteractionMap: Map<number, Interaction> = new Map();
|
|
58
|
+
|
|
59
|
+
_onBeforeProcessingEntry?: (entry: PerformanceEventTiming) => void;
|
|
60
|
+
|
|
61
|
+
_onAfterProcessingINPCandidate?: (interaction: Interaction) => void;
|
|
62
|
+
|
|
63
|
+
_resetInteractions() {
|
|
64
|
+
prevInteractionCount = getInteractionCount();
|
|
65
|
+
this._longestInteractionList.length = 0;
|
|
66
|
+
this._longestInteractionMap.clear();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Returns the estimated p98 longest interaction based on the stored
|
|
71
|
+
* interaction candidates and the interaction count for the current page.
|
|
72
|
+
*/
|
|
73
|
+
_estimateP98LongestInteraction() {
|
|
74
|
+
const candidateInteractionIndex = Math.min(
|
|
75
|
+
this._longestInteractionList.length - 1,
|
|
76
|
+
Math.floor(getInteractionCountForNavigation() / 50),
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
return this._longestInteractionList[candidateInteractionIndex];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Takes a performance entry and adds it to the list of worst interactions
|
|
84
|
+
* if its duration is long enough to make it among the worst. If the
|
|
85
|
+
* entry is part of an existing interaction, it is merged and the latency
|
|
86
|
+
* and entries list is updated as needed.
|
|
87
|
+
*/
|
|
88
|
+
_processEntry(entry: PerformanceEventTiming) {
|
|
89
|
+
this._onBeforeProcessingEntry?.(entry);
|
|
90
|
+
|
|
91
|
+
// Skip further processing for entries that cannot be INP candidates.
|
|
92
|
+
if (!(entry.interactionId || entry.entryType === 'first-input')) return;
|
|
93
|
+
|
|
94
|
+
// The least-long of the 10 longest interactions.
|
|
95
|
+
const minLongestInteraction = this._longestInteractionList.at(-1);
|
|
96
|
+
|
|
97
|
+
let interaction = this._longestInteractionMap.get(entry.interactionId!);
|
|
98
|
+
|
|
99
|
+
// Only process the entry if it's possibly one of the ten longest,
|
|
100
|
+
// or if it's part of an existing interaction.
|
|
101
|
+
if (
|
|
102
|
+
interaction ||
|
|
103
|
+
this._longestInteractionList.length < MAX_INTERACTIONS_TO_CONSIDER ||
|
|
104
|
+
// If the above conditions are false, `minLongestInteraction` will be set.
|
|
105
|
+
entry.duration > minLongestInteraction!._latency
|
|
106
|
+
) {
|
|
107
|
+
// If the interaction already exists, update it. Otherwise create one.
|
|
108
|
+
if (interaction) {
|
|
109
|
+
// If the new entry has a longer duration, replace the old entries,
|
|
110
|
+
// otherwise add to the array.
|
|
111
|
+
if (entry.duration > interaction._latency) {
|
|
112
|
+
interaction.entries = [entry];
|
|
113
|
+
interaction._latency = entry.duration;
|
|
114
|
+
} else if (
|
|
115
|
+
entry.duration === interaction._latency &&
|
|
116
|
+
entry.startTime === interaction.entries[0].startTime
|
|
117
|
+
) {
|
|
118
|
+
interaction.entries.push(entry);
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
interaction = {
|
|
122
|
+
id: entry.interactionId!,
|
|
123
|
+
entries: [entry],
|
|
124
|
+
_latency: entry.duration,
|
|
125
|
+
};
|
|
126
|
+
this._longestInteractionMap.set(interaction.id, interaction);
|
|
127
|
+
this._longestInteractionList.push(interaction);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Sort the entries by latency (descending) and keep only the top ten.
|
|
131
|
+
this._longestInteractionList.sort((a, b) => b._latency - a._latency);
|
|
132
|
+
if (this._longestInteractionList.length > MAX_INTERACTIONS_TO_CONSIDER) {
|
|
133
|
+
const removedInteractions = this._longestInteractionList.splice(
|
|
134
|
+
MAX_INTERACTIONS_TO_CONSIDER,
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
for (const interaction of removedInteractions) {
|
|
138
|
+
this._longestInteractionMap.delete(interaction.id);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Call any post-processing on the interaction
|
|
143
|
+
this._onAfterProcessingINPCandidate?.(interaction);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -14,13 +14,10 @@
|
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
export {
|
|
18
|
-
|
|
19
|
-
* @deprecated Use `onINP()` instead.
|
|
20
|
-
*/
|
|
21
|
-
onFID,
|
|
22
|
-
} from './onFID.js';
|
|
17
|
+
export class LCPEntryManager {
|
|
18
|
+
_onBeforeProcessingEntry?: (entry: LargestContentfulPaint) => void;
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
_processEntry(entry: LargestContentfulPaint) {
|
|
21
|
+
this._onBeforeProcessingEntry?.(entry);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2024 Google LLC
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* https://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export class LayoutShiftManager {
|
|
18
|
+
_onAfterProcessingUnexpectedShift?: (entry: LayoutShift) => void;
|
|
19
|
+
|
|
20
|
+
_sessionValue = 0;
|
|
21
|
+
_sessionEntries: LayoutShift[] = [];
|
|
22
|
+
|
|
23
|
+
_processEntry(entry: LayoutShift) {
|
|
24
|
+
// Only count layout shifts without recent user input.
|
|
25
|
+
if (entry.hadRecentInput) return;
|
|
26
|
+
|
|
27
|
+
const firstSessionEntry = this._sessionEntries[0];
|
|
28
|
+
const lastSessionEntry = this._sessionEntries.at(-1);
|
|
29
|
+
|
|
30
|
+
// If the entry occurred less than 1 second after the previous entry
|
|
31
|
+
// and less than 5 seconds after the first entry in the session,
|
|
32
|
+
// include the entry in the current session. Otherwise, start a new
|
|
33
|
+
// session.
|
|
34
|
+
if (
|
|
35
|
+
this._sessionValue &&
|
|
36
|
+
firstSessionEntry &&
|
|
37
|
+
lastSessionEntry &&
|
|
38
|
+
entry.startTime - lastSessionEntry.startTime < 1000 &&
|
|
39
|
+
entry.startTime - firstSessionEntry.startTime < 5000
|
|
40
|
+
) {
|
|
41
|
+
this._sessionValue += entry.value;
|
|
42
|
+
this._sessionEntries.push(entry);
|
|
43
|
+
} else {
|
|
44
|
+
this._sessionValue = entry.value;
|
|
45
|
+
this._sessionEntries = [entry];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
this._onAfterProcessingUnexpectedShift?.(entry);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -40,7 +40,7 @@ export const bindReporter = <MetricName extends MetricType['name']>(
|
|
|
40
40
|
return (forceReport?: boolean) => {
|
|
41
41
|
if (metric.value >= 0) {
|
|
42
42
|
if (forceReport || reportAllChanges) {
|
|
43
|
-
delta = metric.value - (prevValue
|
|
43
|
+
delta = metric.value - (prevValue ?? 0);
|
|
44
44
|
|
|
45
45
|
// Report the metric if there's a non-zero delta or if no previous
|
|
46
46
|
// value exists (which can happen in the case of the document becoming
|
|
@@ -15,18 +15,15 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
export const getNavigationEntry = (): PerformanceNavigationTiming | void => {
|
|
18
|
-
const navigationEntry =
|
|
19
|
-
self.performance &&
|
|
20
|
-
performance.getEntriesByType &&
|
|
21
|
-
performance.getEntriesByType('navigation')[0];
|
|
18
|
+
const navigationEntry = performance.getEntriesByType('navigation')[0];
|
|
22
19
|
|
|
23
20
|
// Check to ensure the `responseStart` property is present and valid.
|
|
24
|
-
// In some cases
|
|
21
|
+
// In some cases a zero value is reported by the browser (for
|
|
25
22
|
// privacy/security reasons), and in other cases (bugs) the value is
|
|
26
23
|
// negative or is larger than the current page time. Ignore these cases:
|
|
27
|
-
// https://github.com/GoogleChrome/web-vitals/issues/137
|
|
28
|
-
// https://github.com/GoogleChrome/web-vitals/issues/162
|
|
29
|
-
// https://github.com/GoogleChrome/web-vitals/issues/275
|
|
24
|
+
// - https://github.com/GoogleChrome/web-vitals/issues/137
|
|
25
|
+
// - https://github.com/GoogleChrome/web-vitals/issues/162
|
|
26
|
+
// - https://github.com/GoogleChrome/web-vitals/issues/275
|
|
30
27
|
if (
|
|
31
28
|
navigationEntry &&
|
|
32
29
|
navigationEntry.responseStart > 0 &&
|
|
@@ -21,27 +21,27 @@ const getName = (node: Node) => {
|
|
|
21
21
|
: name.toUpperCase().replace(/^#/, '');
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
const MAX_LEN = 100;
|
|
25
|
+
|
|
26
|
+
export const getSelector = (node: Node | null) => {
|
|
25
27
|
let sel = '';
|
|
26
28
|
|
|
27
29
|
try {
|
|
28
|
-
while (node
|
|
30
|
+
while (node?.nodeType !== 9) {
|
|
29
31
|
const el: Element = node as Element;
|
|
30
32
|
const part = el.id
|
|
31
33
|
? '#' + el.id
|
|
32
|
-
: getName(el)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
el.classList.value.trim().length
|
|
37
|
-
? '.' + el.classList.value.trim().replace(/\s+/g, '.')
|
|
38
|
-
: '');
|
|
39
|
-
if (sel.length + part.length > (maxLen || 100) - 1) return sel || part;
|
|
34
|
+
: [getName(el), ...Array.from(el.classList).sort()].join('.');
|
|
35
|
+
if (sel.length + part.length > MAX_LEN - 1) {
|
|
36
|
+
return sel || part;
|
|
37
|
+
}
|
|
40
38
|
sel = sel ? part + '>' + sel : part;
|
|
41
|
-
if (el.id)
|
|
39
|
+
if (el.id) {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
42
|
node = el.parentNode;
|
|
43
43
|
}
|
|
44
|
-
} catch
|
|
44
|
+
} catch {
|
|
45
45
|
// Do nothing...
|
|
46
46
|
}
|
|
47
47
|
return sel;
|
|
@@ -15,8 +15,10 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import {onBFCacheRestore} from './bfcache.js';
|
|
18
|
+
import {getActivationStart} from './getActivationStart.js';
|
|
18
19
|
|
|
19
20
|
let firstHiddenTime = -1;
|
|
21
|
+
const onHiddenFunctions: Set<() => void> = new Set();
|
|
20
22
|
|
|
21
23
|
const initHiddenTime = () => {
|
|
22
24
|
// If the document is hidden when this code runs, assume it was always
|
|
@@ -30,45 +32,63 @@ const initHiddenTime = () => {
|
|
|
30
32
|
};
|
|
31
33
|
|
|
32
34
|
const onVisibilityUpdate = (event: Event) => {
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// be a 'prerenderingchange' event, and the fact that the document is
|
|
41
|
-
// still 'hidden' from the above check means the tab was activated
|
|
42
|
-
// in a background state and so has always been hidden.
|
|
43
|
-
firstHiddenTime = event.type === 'visibilitychange' ? event.timeStamp : 0;
|
|
35
|
+
// Handle changes to hidden state
|
|
36
|
+
if (document.visibilityState === 'hidden') {
|
|
37
|
+
if (event.type === 'visibilitychange') {
|
|
38
|
+
for (const onHiddenFunction of onHiddenFunctions) {
|
|
39
|
+
onHiddenFunction();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
44
42
|
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
addEventListener('prerenderingchange', onVisibilityUpdate, true);
|
|
57
|
-
};
|
|
43
|
+
// If the document is 'hidden' and no previous hidden timestamp has been
|
|
44
|
+
// set (so is infinity), update it based on the current event data.
|
|
45
|
+
if (!isFinite(firstHiddenTime)) {
|
|
46
|
+
// If the event is a 'visibilitychange' event, it means the page was
|
|
47
|
+
// visible prior to this change, so the event timestamp is the first
|
|
48
|
+
// hidden time.
|
|
49
|
+
// However, if the event is not a 'visibilitychange' event, then it must
|
|
50
|
+
// be a 'prerenderingchange' event, and the fact that the document is
|
|
51
|
+
// still 'hidden' from the above check means the tab was activated
|
|
52
|
+
// in a background state and so has always been hidden.
|
|
53
|
+
firstHiddenTime = event.type === 'visibilitychange' ? event.timeStamp : 0;
|
|
58
54
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
// We no longer need the `prerenderingchange` event listener now we've
|
|
56
|
+
// set an initial init time so remove that
|
|
57
|
+
// (we'll keep the visibilitychange one for onHiddenFunction above)
|
|
58
|
+
removeEventListener('prerenderingchange', onVisibilityUpdate, true);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
62
61
|
};
|
|
63
62
|
|
|
64
63
|
export const getVisibilityWatcher = () => {
|
|
65
64
|
if (firstHiddenTime < 0) {
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
// Check if we have a previous hidden `visibility-state` performance entry.
|
|
66
|
+
const activationStart = getActivationStart();
|
|
67
|
+
/* eslint-disable indent */
|
|
68
|
+
const firstVisibilityStateHiddenTime = !document.prerendering
|
|
69
|
+
? globalThis.performance
|
|
70
|
+
.getEntriesByType('visibility-state')
|
|
71
|
+
.filter(
|
|
72
|
+
(e) => e.name === 'hidden' && e.startTime > activationStart,
|
|
73
|
+
)[0]?.startTime
|
|
74
|
+
: undefined;
|
|
75
|
+
/* eslint-enable indent */
|
|
76
|
+
|
|
77
|
+
// Prefer that, but if it's not available and the document is hidden when
|
|
78
|
+
// this code runs, assume it was hidden since navigation start. This isn't
|
|
79
|
+
// a perfect heuristic, but it's the best we can do until the
|
|
80
|
+
// `visibility-state` performance entry becomes available in all browsers.
|
|
81
|
+
firstHiddenTime = firstVisibilityStateHiddenTime ?? initHiddenTime();
|
|
82
|
+
|
|
83
|
+
// Listen for visibility changes so we can handle things like bfcache
|
|
84
|
+
// restores and/or prerender without having to examine individual
|
|
85
|
+
// timestamps in detail and also for onHidden function calls.
|
|
86
|
+
addEventListener('visibilitychange', onVisibilityUpdate, true);
|
|
87
|
+
// IMPORTANT: when a page is prerendering, its `visibilityState` is
|
|
88
|
+
// 'hidden', so in order to account for cases where this module checks for
|
|
89
|
+
// visibility during prerendering, an additional check after prerendering
|
|
90
|
+
// completes is also required.
|
|
91
|
+
addEventListener('prerenderingchange', onVisibilityUpdate, true);
|
|
72
92
|
|
|
73
93
|
// Reset the time on bfcache restores.
|
|
74
94
|
onBFCacheRestore(() => {
|
|
@@ -77,13 +97,15 @@ export const getVisibilityWatcher = () => {
|
|
|
77
97
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=1133363
|
|
78
98
|
setTimeout(() => {
|
|
79
99
|
firstHiddenTime = initHiddenTime();
|
|
80
|
-
|
|
81
|
-
}, 0);
|
|
100
|
+
});
|
|
82
101
|
});
|
|
83
102
|
}
|
|
84
103
|
return {
|
|
85
104
|
get firstHiddenTime() {
|
|
86
105
|
return firstHiddenTime;
|
|
87
106
|
},
|
|
107
|
+
onHidden(cb: () => void) {
|
|
108
|
+
onHiddenFunctions.add(cb);
|
|
109
|
+
},
|
|
88
110
|
};
|
|
89
111
|
};
|