chrome-devtools-frontend 1.0.1556696 → 1.0.1559913
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/front_end/Images/src/container.svg +4 -0
- package/front_end/core/common/Gzip.ts +15 -0
- package/front_end/core/common/Object.ts +5 -1
- package/front_end/core/host/ResourceLoader.ts +1 -1
- package/front_end/core/host/UserMetrics.ts +3 -1
- package/front_end/core/sdk/CSSMetadata.ts +6 -6
- package/front_end/core/sdk/CSSModel.ts +2 -2
- package/front_end/core/sdk/DOMModel.ts +14 -3
- package/front_end/core/sdk/NetworkManager.ts +0 -7
- package/front_end/core/sdk/SourceMap.ts +16 -2
- package/front_end/core/sdk/SourceMapManager.ts +1 -1
- package/front_end/core/sdk/SourceMapScopesInfo.ts +11 -4
- package/front_end/entrypoints/formatter_worker/FormatterActions.ts +1 -0
- package/front_end/entrypoints/formatter_worker/ScopeParser.ts +51 -8
- package/front_end/entrypoints/main/GlobalAiButton.ts +5 -1
- package/front_end/generated/Deprecation.ts +0 -7
- package/front_end/generated/InspectorBackendCommands.ts +5 -4
- package/front_end/generated/SupportedCSSProperties.js +64 -32
- package/front_end/generated/protocol-mapping.d.ts +9 -0
- package/front_end/generated/protocol-proxy-api.d.ts +7 -0
- package/front_end/generated/protocol.ts +23 -1
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +1 -1
- package/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.ts +11 -7
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +3 -3
- package/front_end/models/bindings/CompilerScriptMapping.ts +7 -6
- package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +4 -4
- package/front_end/models/javascript_metadata/NativeFunctions.js +2 -2
- package/front_end/models/stack_trace/StackTraceImpl.ts +5 -3
- package/front_end/models/stack_trace/StackTraceModel.ts +53 -40
- package/front_end/models/trace/EventsSerializer.ts +8 -2
- package/front_end/models/trace/LanternComputationData.ts +4 -3
- package/front_end/models/trace/Processor.ts +6 -5
- package/front_end/models/trace/Styles.ts +10 -1
- package/front_end/models/trace/handlers/LargestImagePaintHandler.ts +2 -2
- package/front_end/models/trace/handlers/LayoutShiftsHandler.ts +2 -2
- package/front_end/models/trace/handlers/MetaHandler.ts +14 -0
- package/front_end/models/trace/handlers/PageLoadMetricsHandler.ts +54 -34
- package/front_end/models/trace/helpers/Timing.ts +8 -1
- package/front_end/models/trace/insights/Common.ts +1 -1
- package/front_end/models/trace/insights/LCPBreakdown.ts +4 -4
- package/front_end/models/trace/insights/LCPDiscovery.ts +3 -3
- package/front_end/models/trace/insights/RenderBlocking.ts +1 -1
- package/front_end/models/trace/insights/types.ts +1 -1
- package/front_end/models/trace/types/TraceEvents.ts +62 -10
- package/front_end/panels/application/AppManifestView.ts +134 -223
- package/front_end/panels/application/CookieItemsView.ts +1 -0
- package/front_end/panels/application/SharedStorageTreeElement.ts +3 -0
- package/front_end/panels/application/appManifestView.css +1 -1
- package/front_end/panels/common/AiCodeGenerationTeaser.ts +48 -12
- package/front_end/panels/common/aiCodeGenerationTeaser.css +14 -0
- package/front_end/panels/common/common.ts +1 -1
- package/front_end/panels/console/ConsoleViewMessage.ts +4 -3
- package/front_end/panels/console/consoleView.css +1 -1
- package/front_end/panels/elements/CSSRuleValidator.ts +38 -0
- package/front_end/panels/elements/ElementsTreeElement.ts +108 -58
- package/front_end/panels/elements/ElementsTreeOutline.ts +0 -17
- package/front_end/panels/elements/ElementsTreeOutlineRenderer.ts +7 -1
- package/front_end/panels/elements/StylesSidebarPane.ts +15 -4
- package/front_end/panels/elements/components/AdornerManager.ts +8 -0
- package/front_end/panels/emulation/DeviceModeToolbar.ts +3 -1
- package/front_end/panels/issues/AffectedResourcesView.ts +0 -1
- package/front_end/panels/lighthouse/LighthousePanel.ts +10 -0
- package/front_end/panels/lighthouse/lighthousePanel.css +46 -3
- package/front_end/panels/network/NetworkLogViewColumns.ts +9 -9
- package/front_end/panels/network/RequestCookiesView.ts +125 -141
- package/front_end/panels/network/components/RequestHeadersView.ts +2 -2
- package/front_end/panels/network/requestCookiesView.css +22 -20
- package/front_end/panels/recorder/components/RecordingView.ts +3 -3
- package/front_end/panels/recorder/components/StepView.ts +2 -1
- package/front_end/panels/settings/keybindsSettingsTab.css +4 -0
- package/front_end/panels/sources/CallStackSidebarPane.ts +7 -3
- package/front_end/panels/sources/DebuggerPausedMessage.ts +125 -90
- package/front_end/panels/sources/SourcesPanel.ts +10 -7
- package/front_end/panels/sources/debuggerPausedMessage.css +8 -0
- package/front_end/panels/timeline/StatusDialog.ts +4 -3
- package/front_end/panels/timeline/TimelineFlameChartNetworkDataProvider.ts +3 -16
- package/front_end/panels/timeline/TimelineFlameChartView.ts +64 -21
- package/front_end/panels/timeline/TimelinePanel.ts +71 -24
- package/front_end/panels/timeline/TimelineUIUtils.ts +28 -2
- package/front_end/panels/timeline/TimingsTrackAppender.ts +3 -1
- package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +1 -1
- package/front_end/panels/timeline/components/insights/RenderBlocking.ts +6 -4
- package/front_end/panels/timeline/components/sidebarInsightsTab.css +2 -0
- package/front_end/panels/timeline/overlays/OverlaysImpl.ts +4 -0
- package/front_end/panels/timeline/timelinePanel.css +8 -1
- package/front_end/panels/timeline/utils/EntryNodes.ts +2 -1
- package/front_end/third_party/acorn/estree-legacy.d.ts +2 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.d.ts +12 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts +14 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Browser.d.ts +3 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Browser.js +6 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.d.ts +0 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.js +0 -20
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/HTTPRequest.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts +3 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js +10 -14
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.d.ts +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.js +14 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/core/BrowsingContext.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts +3 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js +12 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/EmulationManager.d.ts +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/EmulationManager.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/EmulationManager.js +22 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/EmulationManager.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts +3 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js +9 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.d.ts +26 -0
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +72 -15
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.d.ts +12 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts +14 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Browser.d.ts +3 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Browser.js +6 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.d.ts +0 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.js +0 -20
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/HTTPRequest.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts +3 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js +11 -15
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.d.ts +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.js +14 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/core/BrowsingContext.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts +3 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js +12 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/EmulationManager.d.ts +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/EmulationManager.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/EmulationManager.js +22 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/EmulationManager.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts +3 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js +9 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/types.d.ts +26 -0
- package/front_end/third_party/puppeteer/package/package.json +1 -1
- package/front_end/third_party/puppeteer/package/src/api/Browser.ts +18 -0
- package/front_end/third_party/puppeteer/package/src/api/Page.ts +16 -2
- package/front_end/third_party/puppeteer/package/src/bidi/Browser.ts +13 -0
- package/front_end/third_party/puppeteer/package/src/bidi/HTTPRequest.ts +0 -33
- package/front_end/third_party/puppeteer/package/src/bidi/Page.ts +14 -28
- package/front_end/third_party/puppeteer/package/src/bidi/core/BrowsingContext.ts +19 -0
- package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +19 -0
- package/front_end/third_party/puppeteer/package/src/cdp/EmulationManager.ts +30 -0
- package/front_end/third_party/puppeteer/package/src/cdp/Page.ts +15 -6
- package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/ui/components/icon_button/iconButton.css +3 -1
- package/front_end/ui/components/report_view/ReportView.ts +11 -2
- package/front_end/ui/components/report_view/report.css +16 -0
- package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +202 -32
- package/front_end/ui/components/text_editor/config.ts +6 -6
- package/front_end/ui/legacy/ContextMenu.ts +11 -2
- package/front_end/ui/legacy/SearchableView.ts +11 -5
- package/front_end/ui/legacy/SplitWidget.ts +1 -1
- package/front_end/ui/legacy/TextPrompt.ts +1 -1
- package/front_end/ui/legacy/Toolbar.ts +4 -0
- package/front_end/ui/legacy/UIUtils.ts +0 -2
- package/front_end/ui/legacy/components/cookie_table/CookiesTable.ts +18 -3
- package/front_end/ui/legacy/components/data_grid/DataGrid.ts +3 -3
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +6 -0
- package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +43 -9
- package/front_end/ui/visual_logging/KnownContextValues.ts +13 -0
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
+
import * as Common from '../../core/common/common.js';
|
|
5
6
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
6
7
|
import type * as Protocol from '../../generated/protocol.js';
|
|
7
8
|
|
|
@@ -32,6 +33,7 @@ export type TranslateRawFrames = (frames: readonly RawFrame[], target: SDK.Targe
|
|
|
32
33
|
*/
|
|
33
34
|
export class StackTraceModel extends SDK.SDKModel.SDKModel<unknown> {
|
|
34
35
|
readonly #trie = new Trie();
|
|
36
|
+
readonly #mutex = new Common.Mutex.Mutex();
|
|
35
37
|
|
|
36
38
|
/** @returns the {@link StackTraceModel} for the target, or the model for the primaryPageTarget when passing null/undefined */
|
|
37
39
|
static #modelForTarget(target: SDK.Target.Target|null|undefined): StackTraceModel {
|
|
@@ -45,7 +47,7 @@ export class StackTraceModel extends SDK.SDKModel.SDKModel<unknown> {
|
|
|
45
47
|
async createFromProtocolRuntime(stackTrace: Protocol.Runtime.StackTrace, rawFramesToUIFrames: TranslateRawFrames):
|
|
46
48
|
Promise<StackTrace.StackTrace.StackTrace> {
|
|
47
49
|
const [syncFragment, asyncFragments] = await Promise.all([
|
|
48
|
-
this.#
|
|
50
|
+
this.#createFragment(stackTrace.callFrames, rawFramesToUIFrames),
|
|
49
51
|
this.#createAsyncFragments(stackTrace, rawFramesToUIFrames),
|
|
50
52
|
]);
|
|
51
53
|
|
|
@@ -65,53 +67,51 @@ export class StackTraceModel extends SDK.SDKModel.SDKModel<unknown> {
|
|
|
65
67
|
|
|
66
68
|
/** Trigger re-translation of all fragments with the provide script in their call stack */
|
|
67
69
|
async scriptInfoChanged(script: SDK.Script.Script, translateRawFrames: TranslateRawFrames): Promise<void> {
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
70
|
+
const release = await this.#mutex.acquire();
|
|
71
|
+
try {
|
|
72
|
+
const translatePromises: Array<Promise<unknown>> = [];
|
|
73
|
+
let stackTracesToUpdate = new Set<AnyStackTraceImpl>();
|
|
74
|
+
|
|
75
|
+
for (const fragment of this.#affectedFragments(script)) {
|
|
76
|
+
// We trigger re-translation only for fragments of leaf-nodes. Any fragment along the ancestor-chain
|
|
77
|
+
// is re-translated as a side-effect.
|
|
78
|
+
// We just need to remember the stack traces of the skipped over fragments, so we can send the
|
|
79
|
+
// UPDATED event also to them.
|
|
80
|
+
if (fragment.node.children.length === 0) {
|
|
81
|
+
translatePromises.push(this.#translateFragment(fragment, translateRawFrames));
|
|
82
|
+
}
|
|
83
|
+
stackTracesToUpdate = stackTracesToUpdate.union(fragment.stackTraces);
|
|
78
84
|
}
|
|
79
|
-
stackTracesToUpdate = stackTracesToUpdate.union(fragment.stackTraces);
|
|
80
|
-
}
|
|
81
85
|
|
|
82
|
-
|
|
86
|
+
await Promise.all(translatePromises);
|
|
83
87
|
|
|
84
|
-
|
|
85
|
-
|
|
88
|
+
for (const stackTrace of stackTracesToUpdate) {
|
|
89
|
+
stackTrace.dispatchEventToListeners(StackTrace.StackTrace.Events.UPDATED);
|
|
90
|
+
}
|
|
91
|
+
} finally {
|
|
92
|
+
release();
|
|
86
93
|
}
|
|
87
94
|
}
|
|
88
95
|
|
|
89
|
-
async #createSyncFragment(stackTrace: Protocol.Runtime.StackTrace, rawFramesToUIFrames: TranslateRawFrames):
|
|
90
|
-
Promise<FragmentImpl> {
|
|
91
|
-
const fragment = this.#createFragment(stackTrace.callFrames);
|
|
92
|
-
await this.#translateFragment(fragment, rawFramesToUIFrames);
|
|
93
|
-
return fragment;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
96
|
async #createDebuggableFragment(
|
|
97
97
|
pausedDetails: SDK.DebuggerModel.DebuggerPausedDetails,
|
|
98
98
|
rawFramesToUIFrames: TranslateRawFrames): Promise<DebuggableFragmentImpl> {
|
|
99
|
-
const fragment = this.#createFragment(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
99
|
+
const fragment = await this.#createFragment(
|
|
100
|
+
pausedDetails.callFrames.map(frame => ({
|
|
101
|
+
scriptId: frame.script.scriptId,
|
|
102
|
+
url: frame.script.sourceURL,
|
|
103
|
+
functionName: frame.functionName,
|
|
104
|
+
lineNumber: frame.location().lineNumber,
|
|
105
|
+
columnNumber: frame.location().columnNumber,
|
|
106
|
+
})),
|
|
107
|
+
rawFramesToUIFrames);
|
|
107
108
|
return new DebuggableFragmentImpl(fragment, pausedDetails.callFrames);
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
async #createAsyncFragments(
|
|
111
112
|
stackTraceOrPausedEvent: Protocol.Runtime.StackTrace|SDK.DebuggerModel.DebuggerPausedDetails,
|
|
112
113
|
rawFramesToUIFrames: TranslateRawFrames): Promise<AsyncFragmentImpl[]> {
|
|
113
|
-
const asyncFragments: AsyncFragmentImpl
|
|
114
|
-
const translatePromises: Array<Promise<unknown>> = [];
|
|
114
|
+
const asyncFragments: Array<Promise<AsyncFragmentImpl>> = [];
|
|
115
115
|
|
|
116
116
|
const debuggerModel = this.target().model(SDK.DebuggerModel.DebuggerModel);
|
|
117
117
|
if (debuggerModel) {
|
|
@@ -122,18 +122,31 @@ export class StackTraceModel extends SDK.SDKModel.SDKModel<unknown> {
|
|
|
122
122
|
continue;
|
|
123
123
|
}
|
|
124
124
|
const model = StackTraceModel.#modelForTarget(target);
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
125
|
+
const asyncFragmentPromise =
|
|
126
|
+
model.#createFragment(asyncStackTrace.callFrames, rawFramesToUIFrames)
|
|
127
|
+
.then(fragment => new AsyncFragmentImpl(asyncStackTrace.description ?? '', fragment));
|
|
128
|
+
asyncFragments.push(asyncFragmentPromise);
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
131
|
|
|
131
|
-
await Promise.all(
|
|
132
|
-
return asyncFragments;
|
|
132
|
+
return await Promise.all(asyncFragments);
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
#createFragment(frames: RawFrame[]): FragmentImpl {
|
|
136
|
-
|
|
135
|
+
async #createFragment(frames: RawFrame[], rawFramesToUIFrames: TranslateRawFrames): Promise<FragmentImpl> {
|
|
136
|
+
const release = await this.#mutex.acquire();
|
|
137
|
+
try {
|
|
138
|
+
const node = this.#trie.insert(frames);
|
|
139
|
+
const requiresTranslation = !Boolean(node.fragment);
|
|
140
|
+
const fragment = FragmentImpl.getOrCreate(node);
|
|
141
|
+
|
|
142
|
+
if (requiresTranslation) {
|
|
143
|
+
await this.#translateFragment(fragment, rawFramesToUIFrames);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return fragment;
|
|
147
|
+
} finally {
|
|
148
|
+
release();
|
|
149
|
+
}
|
|
137
150
|
}
|
|
138
151
|
|
|
139
152
|
async #translateFragment(fragment: FragmentImpl, rawFramesToUIFrames: TranslateRawFrames): Promise<void> {
|
|
@@ -20,9 +20,15 @@ export class EventsSerializer {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
const rawEvents = Helpers.SyntheticEvents.SyntheticEventsManager.getActiveManager().getRawTraceEvents();
|
|
23
|
+
const isSynthetic = Types.Events.isSyntheticBased(event);
|
|
24
|
+
const index = rawEvents.indexOf(isSynthetic ? event.rawSourceEvent : event);
|
|
25
|
+
if (index === -1) {
|
|
26
|
+
throw new Error(`Unknown trace event: ${event.name}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
23
29
|
const key: Types.File.SyntheticEventKey|Types.File.RawEventKey = Types.Events.isSyntheticBased(event) ?
|
|
24
|
-
`${Types.File.EventKeyType.SYNTHETIC_EVENT}-${
|
|
25
|
-
`${Types.File.EventKeyType.RAW_EVENT}-${
|
|
30
|
+
`${Types.File.EventKeyType.SYNTHETIC_EVENT}-${index}` :
|
|
31
|
+
`${Types.File.EventKeyType.RAW_EVENT}-${index}`;
|
|
26
32
|
if (key.length < 3) {
|
|
27
33
|
return null;
|
|
28
34
|
}
|
|
@@ -10,14 +10,15 @@ import type * as Types from './types/types.js';
|
|
|
10
10
|
|
|
11
11
|
type NetworkRequest = Lantern.Types.NetworkRequest<Types.Events.SyntheticNetworkRequest>;
|
|
12
12
|
|
|
13
|
-
function createProcessedNavigation(
|
|
14
|
-
|
|
13
|
+
function createProcessedNavigation(
|
|
14
|
+
data: Handlers.Types.HandlerData, frameId: string,
|
|
15
|
+
navigation: Types.Events.NavigationStart): Lantern.Types.Simulation.ProcessedNavigation {
|
|
15
16
|
const scoresByNav = data.PageLoadMetrics.metricScoresByFrameId.get(frameId);
|
|
16
17
|
if (!scoresByNav) {
|
|
17
18
|
throw new Lantern.Core.LanternError('missing metric scores for frame');
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
const scores = scoresByNav.get(
|
|
21
|
+
const scores = scoresByNav.get(navigation);
|
|
21
22
|
if (!scores) {
|
|
22
23
|
throw new Lantern.Core.LanternError('missing metric scores for specified navigation');
|
|
23
24
|
}
|
|
@@ -268,7 +268,8 @@ export class TraceProcessor extends EventTarget {
|
|
|
268
268
|
|
|
269
269
|
#createLanternContext(
|
|
270
270
|
data: Handlers.Types.HandlerData, traceEvents: readonly Types.Events.Event[], frameId: string,
|
|
271
|
-
|
|
271
|
+
navigation: Types.Events.NavigationStart,
|
|
272
|
+
options: Types.Configuration.ParseOptions): Insights.Types.LanternContext|undefined {
|
|
272
273
|
// Check for required handlers.
|
|
273
274
|
if (!data.NetworkRequests || !data.Workers || !data.PageLoadMetrics) {
|
|
274
275
|
return;
|
|
@@ -278,7 +279,7 @@ export class TraceProcessor extends EventTarget {
|
|
|
278
279
|
}
|
|
279
280
|
|
|
280
281
|
const navStarts = data.Meta.navigationsByFrameId.get(frameId);
|
|
281
|
-
const navStartIndex = navStarts?.findIndex(n => n
|
|
282
|
+
const navStartIndex = navStarts?.findIndex(n => n === navigation);
|
|
282
283
|
if (!navStarts || navStartIndex === undefined || navStartIndex === -1) {
|
|
283
284
|
throw new Lantern.Core.LanternError('Could not find navigation start');
|
|
284
285
|
}
|
|
@@ -295,7 +296,7 @@ export class TraceProcessor extends EventTarget {
|
|
|
295
296
|
|
|
296
297
|
const requests = LanternComputationData.createNetworkRequests(trace, data, startTime, endTime);
|
|
297
298
|
const graph = LanternComputationData.createGraph(requests, trace, data);
|
|
298
|
-
const processedNavigation = LanternComputationData.createProcessedNavigation(data, frameId,
|
|
299
|
+
const processedNavigation = LanternComputationData.createProcessedNavigation(data, frameId, navigation);
|
|
299
300
|
|
|
300
301
|
const networkAnalysis = Lantern.Core.NetworkAnalyzer.analyze(requests);
|
|
301
302
|
if (!networkAnalysis) {
|
|
@@ -455,7 +456,7 @@ export class TraceProcessor extends EventTarget {
|
|
|
455
456
|
model.frameId = context.frameId;
|
|
456
457
|
const navId = context.navigation?.args.data?.navigationId;
|
|
457
458
|
if (navId) {
|
|
458
|
-
model.
|
|
459
|
+
model.navigation = context.navigation;
|
|
459
460
|
}
|
|
460
461
|
model.createOverlays = () => {
|
|
461
462
|
// @ts-expect-error: model is a union of all possible insight model types.
|
|
@@ -571,7 +572,7 @@ export class TraceProcessor extends EventTarget {
|
|
|
571
572
|
let lantern: Insights.Types.LanternContext|undefined;
|
|
572
573
|
try {
|
|
573
574
|
options.logger?.start('insights:createLanternContext');
|
|
574
|
-
lantern = this.#createLanternContext(data, traceEvents, frameId,
|
|
575
|
+
lantern = this.#createLanternContext(data, traceEvents, frameId, navigation, options);
|
|
575
576
|
} catch (e) {
|
|
576
577
|
// Handle Lantern errors gracefully
|
|
577
578
|
// Don't allow an error in constructing the Lantern graphs to break the rest of the trace processor.
|
|
@@ -879,6 +879,11 @@ export function maybeInitSylesMap(): EventStylesMap {
|
|
|
879
879
|
defaultCategoryStyles.rendering,
|
|
880
880
|
true,
|
|
881
881
|
),
|
|
882
|
+
[Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION]: new TimelineRecordStyle(
|
|
883
|
+
i18nString(UIStrings.largestContentfulPaint),
|
|
884
|
+
defaultCategoryStyles.rendering,
|
|
885
|
+
true,
|
|
886
|
+
),
|
|
882
887
|
|
|
883
888
|
[Types.Events.Name.TIME_STAMP]:
|
|
884
889
|
new TimelineRecordStyle(i18nString(UIStrings.timestamp), defaultCategoryStyles.scripting),
|
|
@@ -1118,7 +1123,7 @@ export function markerDetailsForEvent(event: Types.Events.Event): {
|
|
|
1118
1123
|
color = 'var(--sys-color-green-bright)';
|
|
1119
1124
|
title = Handlers.ModelHandlers.PageLoadMetrics.MetricName.FCP;
|
|
1120
1125
|
}
|
|
1121
|
-
if (Types.Events.
|
|
1126
|
+
if (Types.Events.isAnyLargestContentfulPaintCandidate(event)) {
|
|
1122
1127
|
color = 'var(--sys-color-green)';
|
|
1123
1128
|
title = Handlers.ModelHandlers.PageLoadMetrics.MetricName.LCP;
|
|
1124
1129
|
}
|
|
@@ -1126,6 +1131,10 @@ export function markerDetailsForEvent(event: Types.Events.Event): {
|
|
|
1126
1131
|
color = 'var(--color-text-primary)';
|
|
1127
1132
|
title = Handlers.ModelHandlers.PageLoadMetrics.MetricName.NAV;
|
|
1128
1133
|
}
|
|
1134
|
+
if (Types.Events.isSoftNavigationStart(event)) {
|
|
1135
|
+
color = 'var(--sys-color-blue)';
|
|
1136
|
+
title = Handlers.ModelHandlers.PageLoadMetrics.MetricName.SOFT_NAV;
|
|
1137
|
+
}
|
|
1129
1138
|
if (Types.Events.isMarkDOMContent(event)) {
|
|
1130
1139
|
color = 'var(--color-text-disabled)';
|
|
1131
1140
|
title = Handlers.ModelHandlers.PageLoadMetrics.MetricName.DCL;
|
|
@@ -55,9 +55,9 @@ export async function finalize(): Promise<void> {
|
|
|
55
55
|
const metricScoresByFrameId = pageLoadMetricsData().metricScoresByFrameId;
|
|
56
56
|
|
|
57
57
|
for (const [navigationId, navigation] of navigationsByNavigationId) {
|
|
58
|
-
const lcpMetric = metricScoresByFrameId.get(navigation.args.frame)?.get(
|
|
58
|
+
const lcpMetric = metricScoresByFrameId.get(navigation.args.frame)?.get(navigation)?.get(MetricName.LCP);
|
|
59
59
|
const lcpEvent = lcpMetric?.event;
|
|
60
|
-
if (!lcpEvent || !Types.Events.
|
|
60
|
+
if (!lcpEvent || !Types.Events.isAnyLargestContentfulPaintCandidate(lcpEvent)) {
|
|
61
61
|
continue;
|
|
62
62
|
}
|
|
63
63
|
|
|
@@ -443,7 +443,7 @@ async function buildLayoutShiftsClusters(): Promise<void> {
|
|
|
443
443
|
}
|
|
444
444
|
|
|
445
445
|
let largestScore = 0;
|
|
446
|
-
let worstShiftEvent: Types.Events.
|
|
446
|
+
let worstShiftEvent: Types.Events.SyntheticLayoutShift|null = null;
|
|
447
447
|
|
|
448
448
|
for (const shift of cluster.events) {
|
|
449
449
|
weightedScore += shift.args.data ? shift.args.data.weighted_score_delta : 0;
|
|
@@ -504,7 +504,7 @@ async function buildLayoutShiftsClusters(): Promise<void> {
|
|
|
504
504
|
// Update the cluster's worst layout shift.
|
|
505
505
|
if (worstShiftEvent) {
|
|
506
506
|
cluster.worstShiftEvent = worstShiftEvent;
|
|
507
|
-
cluster.rawSourceEvent = worstShiftEvent;
|
|
507
|
+
cluster.rawSourceEvent = worstShiftEvent.rawSourceEvent;
|
|
508
508
|
}
|
|
509
509
|
|
|
510
510
|
// layout shifts are already sorted by time ascending.
|
|
@@ -59,6 +59,7 @@ let traceBounds: Types.Timing.TraceWindowMicro = makeNewTraceBounds();
|
|
|
59
59
|
*/
|
|
60
60
|
let navigationsByFrameId = new Map<string, Types.Events.NavigationStart[]>();
|
|
61
61
|
let navigationsByNavigationId = new Map<string, Types.Events.NavigationStart>();
|
|
62
|
+
let softNavigationsById = new Map<number, Types.Events.SoftNavigationStart>();
|
|
62
63
|
let finalDisplayUrlByNavigationId = new Map<string, string>();
|
|
63
64
|
let mainFrameNavigations: Types.Events.NavigationStart[] = [];
|
|
64
65
|
|
|
@@ -92,6 +93,7 @@ const CHROME_WEB_TRACE_EVENTS = new Set([
|
|
|
92
93
|
export function reset(): void {
|
|
93
94
|
navigationsByFrameId = new Map();
|
|
94
95
|
navigationsByNavigationId = new Map();
|
|
96
|
+
softNavigationsById = new Map();
|
|
95
97
|
finalDisplayUrlByNavigationId = new Map();
|
|
96
98
|
processNames = new Map();
|
|
97
99
|
mainFrameNavigations = [];
|
|
@@ -324,6 +326,10 @@ export function handleEvent(event: Types.Events.Event): void {
|
|
|
324
326
|
return;
|
|
325
327
|
}
|
|
326
328
|
|
|
329
|
+
if (Types.Events.isSoftNavigationStart(event)) {
|
|
330
|
+
softNavigationsById.set(event.args.context.performanceTimelineNavigationId, event);
|
|
331
|
+
}
|
|
332
|
+
|
|
327
333
|
// Update `finalDisplayUrlByNavigationId` to reflect the latest redirect for each navigation.
|
|
328
334
|
if (Types.Events.isResourceSendRequest(event)) {
|
|
329
335
|
if (event.args.data.resourceType !== 'Document') {
|
|
@@ -445,7 +451,14 @@ export interface MetaHandlerData {
|
|
|
445
451
|
browserThreadId: Types.Events.ThreadID;
|
|
446
452
|
gpuProcessId: Types.Events.ProcessID;
|
|
447
453
|
navigationsByFrameId: Map<string, Types.Events.NavigationStart[]>;
|
|
454
|
+
/**
|
|
455
|
+
* This does not include soft navigations.
|
|
456
|
+
*
|
|
457
|
+
* TODO(crbug.com/414468047): include soft navs here, so that
|
|
458
|
+
* PageLoadMetricsHandler and insights can use this map for all navigation types.
|
|
459
|
+
*/
|
|
448
460
|
navigationsByNavigationId: Map<string, Types.Events.NavigationStart>;
|
|
461
|
+
softNavigationsById: Map<number, Types.Events.SoftNavigationStart>;
|
|
449
462
|
/**
|
|
450
463
|
* The user-visible URL displayed to users in the address bar.
|
|
451
464
|
* This captures:
|
|
@@ -514,6 +527,7 @@ export function data(): MetaHandlerData {
|
|
|
514
527
|
mainFrameURL,
|
|
515
528
|
navigationsByFrameId,
|
|
516
529
|
navigationsByNavigationId,
|
|
530
|
+
softNavigationsById,
|
|
517
531
|
finalDisplayUrlByNavigationId,
|
|
518
532
|
threadsInProcess,
|
|
519
533
|
rendererProcessesByFrame: rendererProcessesByFrameId,
|
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* This handler stores page load metrics, including web vitals,
|
|
7
7
|
* and exports them in the shape of a map with the following shape:
|
|
8
|
-
* Map(FrameId -> Map(
|
|
8
|
+
* Map(FrameId -> Map(navigation -> metrics) )
|
|
9
|
+
*
|
|
10
|
+
* Includes soft navigations.
|
|
9
11
|
*
|
|
10
12
|
* It also exports all markers in a trace in an array.
|
|
11
13
|
*
|
|
@@ -22,14 +24,15 @@ import type {HandlerName} from './types.js';
|
|
|
22
24
|
|
|
23
25
|
// Small helpers to make the below type easier to read.
|
|
24
26
|
type FrameId = string;
|
|
25
|
-
type
|
|
27
|
+
type AnyNavigationStart = Types.Events.NavigationStart|Types.Events.SoftNavigationStart;
|
|
28
|
+
|
|
26
29
|
/**
|
|
27
30
|
* This represents the metric scores for all navigations, for all frames in a trace.
|
|
28
31
|
* Given a frame id, the map points to another map from navigation id to metric scores.
|
|
29
32
|
* The metric scores include the event related to the metric as well as the data regarding
|
|
30
33
|
* the score itself.
|
|
31
34
|
*/
|
|
32
|
-
let metricScoresByFrameId = new Map<FrameId, Map<
|
|
35
|
+
let metricScoresByFrameId = new Map<FrameId, Map<AnyNavigationStart, Map<MetricName, MetricScore>>>();
|
|
33
36
|
|
|
34
37
|
/**
|
|
35
38
|
* Page load events with no associated duration that happened in the
|
|
@@ -54,7 +57,7 @@ let pageLoadEventsArray: Types.Events.PageLoadEvent[] = [];
|
|
|
54
57
|
// trace, we store that and delete the prior event. When we've parsed the
|
|
55
58
|
// entire trace this set will contain all the LCP events that were used - e.g.
|
|
56
59
|
// the candidates that were the actual LCP events.
|
|
57
|
-
let selectedLCPCandidateEvents = new Set<Types.Events.
|
|
60
|
+
let selectedLCPCandidateEvents = new Set<Types.Events.AnyLargestContentfulPaintCandidate>();
|
|
58
61
|
|
|
59
62
|
export function handleEvent(event: Types.Events.Event): void {
|
|
60
63
|
if (!Types.Events.eventIsPageLoadEvent(event)) {
|
|
@@ -64,11 +67,7 @@ export function handleEvent(event: Types.Events.Event): void {
|
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
function storePageLoadMetricAgainstNavigationId(
|
|
67
|
-
navigation:
|
|
68
|
-
const navigationId = navigation.args.data?.navigationId;
|
|
69
|
-
if (!navigationId) {
|
|
70
|
-
throw new Error('Navigation event unexpectedly had no navigation ID.');
|
|
71
|
-
}
|
|
70
|
+
navigation: AnyNavigationStart, event: Types.Events.PageLoadEvent): void {
|
|
72
71
|
const frameId = getFrameIdForPageLoadEvent(event);
|
|
73
72
|
const {rendererProcessesByFrame} = metaHandlerData();
|
|
74
73
|
|
|
@@ -95,7 +94,7 @@ function storePageLoadMetricAgainstNavigationId(
|
|
|
95
94
|
const fcpTime = Types.Timing.Micro(event.ts - navigation.ts);
|
|
96
95
|
const classification = scoreClassificationForFirstContentfulPaint(fcpTime);
|
|
97
96
|
const metricScore = {event, metricName: MetricName.FCP, classification, navigation, timing: fcpTime};
|
|
98
|
-
storeMetricScore(frameId,
|
|
97
|
+
storeMetricScore(frameId, navigation, metricScore);
|
|
99
98
|
return;
|
|
100
99
|
}
|
|
101
100
|
|
|
@@ -103,7 +102,7 @@ function storePageLoadMetricAgainstNavigationId(
|
|
|
103
102
|
const paintTime = Types.Timing.Micro(event.ts - navigation.ts);
|
|
104
103
|
const classification = ScoreClassification.UNCLASSIFIED;
|
|
105
104
|
const metricScore = {event, metricName: MetricName.FP, classification, navigation, timing: paintTime};
|
|
106
|
-
storeMetricScore(frameId,
|
|
105
|
+
storeMetricScore(frameId, navigation, metricScore);
|
|
107
106
|
return;
|
|
108
107
|
}
|
|
109
108
|
|
|
@@ -116,7 +115,7 @@ function storePageLoadMetricAgainstNavigationId(
|
|
|
116
115
|
navigation,
|
|
117
116
|
timing: dclTime,
|
|
118
117
|
};
|
|
119
|
-
storeMetricScore(frameId,
|
|
118
|
+
storeMetricScore(frameId, navigation, metricScore);
|
|
120
119
|
return;
|
|
121
120
|
}
|
|
122
121
|
|
|
@@ -129,7 +128,7 @@ function storePageLoadMetricAgainstNavigationId(
|
|
|
129
128
|
navigation,
|
|
130
129
|
timing: ttiValue,
|
|
131
130
|
};
|
|
132
|
-
storeMetricScore(frameId,
|
|
131
|
+
storeMetricScore(frameId, navigation, tti);
|
|
133
132
|
|
|
134
133
|
const tbtValue = Helpers.Timing.milliToMicro(Types.Timing.Milli(event.args.args.total_blocking_time_ms));
|
|
135
134
|
const tbt = {
|
|
@@ -139,7 +138,7 @@ function storePageLoadMetricAgainstNavigationId(
|
|
|
139
138
|
navigation,
|
|
140
139
|
timing: tbtValue,
|
|
141
140
|
};
|
|
142
|
-
storeMetricScore(frameId,
|
|
141
|
+
storeMetricScore(frameId, navigation, tbt);
|
|
143
142
|
return;
|
|
144
143
|
}
|
|
145
144
|
|
|
@@ -152,11 +151,11 @@ function storePageLoadMetricAgainstNavigationId(
|
|
|
152
151
|
navigation,
|
|
153
152
|
timing: loadTime,
|
|
154
153
|
};
|
|
155
|
-
storeMetricScore(frameId,
|
|
154
|
+
storeMetricScore(frameId, navigation, metricScore);
|
|
156
155
|
return;
|
|
157
156
|
}
|
|
158
157
|
|
|
159
|
-
if (Types.Events.
|
|
158
|
+
if (Types.Events.isAnyLargestContentfulPaintCandidate(event)) {
|
|
160
159
|
const candidateIndex = event.args.data?.candidateIndex;
|
|
161
160
|
if (!candidateIndex) {
|
|
162
161
|
throw new Error('Largest Contentful Paint unexpectedly had no candidateIndex.');
|
|
@@ -170,16 +169,16 @@ function storePageLoadMetricAgainstNavigationId(
|
|
|
170
169
|
timing: lcpTime,
|
|
171
170
|
};
|
|
172
171
|
const metricsByNavigation = Platform.MapUtilities.getWithDefault(metricScoresByFrameId, frameId, () => new Map());
|
|
173
|
-
const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation,
|
|
172
|
+
const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigation, () => new Map());
|
|
174
173
|
const lastLCPCandidate = metrics.get(MetricName.LCP);
|
|
175
174
|
if (lastLCPCandidate === undefined) {
|
|
176
175
|
selectedLCPCandidateEvents.add(lcp.event);
|
|
177
|
-
storeMetricScore(frameId,
|
|
176
|
+
storeMetricScore(frameId, navigation, lcp);
|
|
178
177
|
return;
|
|
179
178
|
}
|
|
180
179
|
const lastLCPCandidateEvent = lastLCPCandidate.event;
|
|
181
180
|
|
|
182
|
-
if (!Types.Events.
|
|
181
|
+
if (!Types.Events.isAnyLargestContentfulPaintCandidate(lastLCPCandidateEvent)) {
|
|
183
182
|
return;
|
|
184
183
|
}
|
|
185
184
|
const lastCandidateIndex = lastLCPCandidateEvent.args.data?.candidateIndex;
|
|
@@ -192,19 +191,22 @@ function storePageLoadMetricAgainstNavigationId(
|
|
|
192
191
|
if (lastCandidateIndex < candidateIndex) {
|
|
193
192
|
selectedLCPCandidateEvents.delete(lastLCPCandidateEvent);
|
|
194
193
|
selectedLCPCandidateEvents.add(lcp.event);
|
|
195
|
-
storeMetricScore(frameId,
|
|
194
|
+
storeMetricScore(frameId, navigation, lcp);
|
|
196
195
|
}
|
|
197
196
|
return;
|
|
198
197
|
}
|
|
199
198
|
if (Types.Events.isLayoutShift(event)) {
|
|
200
199
|
return;
|
|
201
200
|
}
|
|
201
|
+
if (Types.Events.isSoftNavigationStart(event)) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
202
204
|
return Platform.assertNever(event, `Unexpected event type: ${event}`);
|
|
203
205
|
}
|
|
204
206
|
|
|
205
|
-
function storeMetricScore(frameId: string,
|
|
207
|
+
function storeMetricScore(frameId: string, navigation: AnyNavigationStart, metricScore: MetricScore): void {
|
|
206
208
|
const metricsByNavigation = Platform.MapUtilities.getWithDefault(metricScoresByFrameId, frameId, () => new Map());
|
|
207
|
-
const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation,
|
|
209
|
+
const metrics = Platform.MapUtilities.getWithDefault(metricsByNavigation, navigation, () => new Map());
|
|
208
210
|
// If an entry with that metric name is present, delete it so that the new entry that
|
|
209
211
|
// will replace it is added at the end of the map. This way we guarantee the map entries
|
|
210
212
|
// are ordered in ASC manner by timestamp.
|
|
@@ -214,8 +216,9 @@ function storeMetricScore(frameId: string, navigationId: string, metricScore: Me
|
|
|
214
216
|
|
|
215
217
|
export function getFrameIdForPageLoadEvent(event: Types.Events.PageLoadEvent): string {
|
|
216
218
|
if (Types.Events.isFirstContentfulPaint(event) || Types.Events.isInteractiveTime(event) ||
|
|
217
|
-
Types.Events.
|
|
218
|
-
Types.Events.
|
|
219
|
+
Types.Events.isAnyLargestContentfulPaintCandidate(event) || Types.Events.isNavigationStart(event) ||
|
|
220
|
+
Types.Events.isSoftNavigationStart(event) || Types.Events.isLayoutShift(event) ||
|
|
221
|
+
Types.Events.isFirstPaint(event)) {
|
|
219
222
|
return event.args.frame;
|
|
220
223
|
}
|
|
221
224
|
if (Types.Events.isMarkDOMContent(event) || Types.Events.isMarkLoad(event)) {
|
|
@@ -228,16 +231,23 @@ export function getFrameIdForPageLoadEvent(event: Types.Events.PageLoadEvent): s
|
|
|
228
231
|
Platform.assertNever(event, `Unexpected event type: ${event}`);
|
|
229
232
|
}
|
|
230
233
|
|
|
231
|
-
function getNavigationForPageLoadEvent(event: Types.Events.PageLoadEvent):
|
|
232
|
-
if (Types.Events.isFirstContentfulPaint(event) || Types.Events.
|
|
234
|
+
function getNavigationForPageLoadEvent(event: Types.Events.PageLoadEvent): AnyNavigationStart|null {
|
|
235
|
+
if (Types.Events.isFirstContentfulPaint(event) || Types.Events.isAnyLargestContentfulPaintCandidate(event) ||
|
|
233
236
|
Types.Events.isFirstPaint(event)) {
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
+
const {navigationsByNavigationId, softNavigationsById} = metaHandlerData();
|
|
238
|
+
let navigation;
|
|
239
|
+
if (event.name === Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION &&
|
|
240
|
+
event.args.data?.performanceTimelineNavigationId) {
|
|
241
|
+
navigation = softNavigationsById.get(event.args.data.performanceTimelineNavigationId);
|
|
237
242
|
}
|
|
238
|
-
|
|
239
|
-
|
|
243
|
+
if (!navigation) {
|
|
244
|
+
const navigationId = event.args.data?.navigationId;
|
|
245
|
+
if (!navigationId) {
|
|
246
|
+
throw new Error('Trace event unexpectedly had no navigation ID.');
|
|
247
|
+
}
|
|
240
248
|
|
|
249
|
+
navigation = navigationsByNavigationId.get(navigationId);
|
|
250
|
+
}
|
|
241
251
|
if (!navigation) {
|
|
242
252
|
// This event's navigation has been filtered out by the meta handler as a noise event.
|
|
243
253
|
return null;
|
|
@@ -245,6 +255,11 @@ function getNavigationForPageLoadEvent(event: Types.Events.PageLoadEvent): Types
|
|
|
245
255
|
return navigation;
|
|
246
256
|
}
|
|
247
257
|
|
|
258
|
+
if (Types.Events.isSoftNavigationStart(event)) {
|
|
259
|
+
const {softNavigationsById} = metaHandlerData();
|
|
260
|
+
return softNavigationsById.get(event.args.context.performanceTimelineNavigationId) ?? null;
|
|
261
|
+
}
|
|
262
|
+
|
|
248
263
|
if (Types.Events.isMarkDOMContent(event) || Types.Events.isInteractiveTime(event) ||
|
|
249
264
|
Types.Events.isLayoutShift(event) || Types.Events.isMarkLoad(event)) {
|
|
250
265
|
const frameId = getFrameIdForPageLoadEvent(event);
|
|
@@ -378,7 +393,8 @@ export async function finalize(): Promise<void> {
|
|
|
378
393
|
const allFinalLCPEvents = gatherFinalLCPEvents();
|
|
379
394
|
const mainFrame = metaHandlerData().mainFrameId;
|
|
380
395
|
// Filter out LCP candidates to use only definitive LCP values
|
|
381
|
-
const allEventsButLCP =
|
|
396
|
+
const allEventsButLCP =
|
|
397
|
+
pageLoadEventsArray.filter(event => !Types.Events.isAnyLargestContentfulPaintCandidate(event));
|
|
382
398
|
const markerEvents = [...allFinalLCPEvents, ...allEventsButLCP].filter(Types.Events.isMarkerEvent);
|
|
383
399
|
// Filter by main frame and sort.
|
|
384
400
|
allMarkerEvents =
|
|
@@ -391,8 +407,10 @@ export interface PageLoadMetricsData {
|
|
|
391
407
|
* Given a frame id, the map points to another map from navigation id to metric scores.
|
|
392
408
|
* The metric scores include the event related to the metric as well as the data regarding
|
|
393
409
|
* the score itself.
|
|
410
|
+
*
|
|
411
|
+
* Includes soft navigations.
|
|
394
412
|
*/
|
|
395
|
-
metricScoresByFrameId: Map<string, Map<
|
|
413
|
+
metricScoresByFrameId: Map<string, Map<AnyNavigationStart, Map<MetricName, MetricScore>>>;
|
|
396
414
|
/**
|
|
397
415
|
* Page load events with no associated duration that happened in the
|
|
398
416
|
* main frame.
|
|
@@ -437,6 +455,8 @@ export const enum MetricName {
|
|
|
437
455
|
CLS = 'CLS',
|
|
438
456
|
// Navigation
|
|
439
457
|
NAV = 'Nav',
|
|
458
|
+
// Soft Navigation (just "Nav" b/c space is limited in flame chart)
|
|
459
|
+
SOFT_NAV = 'Nav',
|
|
440
460
|
// Note: INP is handled in UserInteractionsHandler
|
|
441
461
|
}
|
|
442
462
|
|
|
@@ -445,7 +465,7 @@ export interface MetricScore {
|
|
|
445
465
|
classification: ScoreClassification;
|
|
446
466
|
event?: Types.Events.PageLoadEvent;
|
|
447
467
|
// The last navigation that occurred before this metric score.
|
|
448
|
-
navigation?:
|
|
468
|
+
navigation?: AnyNavigationStart;
|
|
449
469
|
estimated?: boolean;
|
|
450
470
|
timing: Types.Timing.Micro;
|
|
451
471
|
}
|
|
@@ -22,10 +22,17 @@ export function timeStampForEventAdjustedByClosestNavigation(
|
|
|
22
22
|
event: Types.Events.Event,
|
|
23
23
|
traceBounds: Types.Timing.TraceWindowMicro,
|
|
24
24
|
navigationsByNavigationId: Map<string, Types.Events.NavigationStart>,
|
|
25
|
+
softNavigationsById: Map<number, Types.Events.SoftNavigationStart>,
|
|
25
26
|
navigationsByFrameId: Map<string, Types.Events.NavigationStart[]>,
|
|
26
27
|
): Types.Timing.Micro {
|
|
27
28
|
let eventTimeStamp = event.ts - traceBounds.min;
|
|
28
|
-
if (event.
|
|
29
|
+
if (event.name === Types.Events.Name.MARK_LCP_CANDIDATE_FOR_SOFT_NAVIGATION &&
|
|
30
|
+
event.args?.data?.performanceTimelineNavigationId) {
|
|
31
|
+
const navigationForEvent = softNavigationsById.get(event.args.data.performanceTimelineNavigationId);
|
|
32
|
+
if (navigationForEvent) {
|
|
33
|
+
eventTimeStamp = event.ts - navigationForEvent.ts;
|
|
34
|
+
}
|
|
35
|
+
} else if (event.args?.data?.navigationId) {
|
|
29
36
|
const navigationForEvent = navigationsByNavigationId.get(event.args.data.navigationId);
|
|
30
37
|
if (navigationForEvent) {
|
|
31
38
|
eventTimeStamp = event.ts - navigationForEvent.ts;
|
|
@@ -27,7 +27,7 @@ export function getInsight<InsightName extends keyof InsightModels>(
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export function getLCP(insightSet: InsightSet):
|
|
30
|
-
{value: Types.Timing.Micro, event: Types.Events.
|
|
30
|
+
{value: Types.Timing.Micro, event: Types.Events.AnyLargestContentfulPaintCandidate}|null {
|
|
31
31
|
const insight = getInsight(InsightKeys.LCP_BREAKDOWN, insightSet);
|
|
32
32
|
if (!insight || !insight.lcpMs || !insight.lcpEvent) {
|
|
33
33
|
return null;
|
|
@@ -95,7 +95,7 @@ export function isLCPBreakdownInsight(model: InsightModel): model is LCPBreakdow
|
|
|
95
95
|
export type LCPBreakdownInsightModel = InsightModel<typeof UIStrings, {
|
|
96
96
|
lcpMs?: Types.Timing.Milli,
|
|
97
97
|
lcpTs?: Types.Timing.Milli,
|
|
98
|
-
lcpEvent?: Types.Events.
|
|
98
|
+
lcpEvent?: Types.Events.AnyLargestContentfulPaintCandidate,
|
|
99
99
|
/** The network request for the LCP image, if there was one. */
|
|
100
100
|
lcpRequest?: Types.Events.SyntheticNetworkRequest,
|
|
101
101
|
subparts?: LCPSubparts,
|
|
@@ -112,7 +112,7 @@ function anyValuesNaN(...values: number[]): boolean {
|
|
|
112
112
|
*/
|
|
113
113
|
function determineSubparts(
|
|
114
114
|
nav: Types.Events.NavigationStart, docRequest: Types.Events.SyntheticNetworkRequest,
|
|
115
|
-
lcpEvent: Types.Events.
|
|
115
|
+
lcpEvent: Types.Events.AnyLargestContentfulPaintCandidate,
|
|
116
116
|
lcpRequest: Types.Events.SyntheticNetworkRequest|undefined): LCPSubparts|null {
|
|
117
117
|
const firstDocByteTs = calculateDocFirstByteTs(docRequest);
|
|
118
118
|
if (firstDocByteTs === null) {
|
|
@@ -218,13 +218,13 @@ export function generateInsight(
|
|
|
218
218
|
throw new Error('no frame metrics');
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
const navMetrics = frameMetrics.get(context.
|
|
221
|
+
const navMetrics = frameMetrics.get(context.navigation);
|
|
222
222
|
if (!navMetrics) {
|
|
223
223
|
throw new Error('no navigation metrics');
|
|
224
224
|
}
|
|
225
225
|
const metricScore = navMetrics.get(Handlers.ModelHandlers.PageLoadMetrics.MetricName.LCP);
|
|
226
226
|
const lcpEvent = metricScore?.event;
|
|
227
|
-
if (!lcpEvent || !Types.Events.
|
|
227
|
+
if (!lcpEvent || !Types.Events.isAnyLargestContentfulPaintCandidate(lcpEvent)) {
|
|
228
228
|
return finalize({warnings: [InsightWarning.NO_LCP]});
|
|
229
229
|
}
|
|
230
230
|
|