chrome-devtools-frontend 1.0.967728 → 1.0.969882
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/gni/devtools_grd_files.gni +84 -0
- package/front_end/core/host/UserMetrics.ts +2 -1
- package/front_end/core/i18n/locales/en-US.json +24 -0
- package/front_end/core/i18n/locales/en-XL.json +24 -0
- package/front_end/core/root/Runtime.ts +1 -0
- package/front_end/core/sdk/CSSMatchedStyles.ts +1 -1
- package/front_end/core/sdk/ChildTargetManager.ts +2 -2
- package/front_end/core/sdk/Connections.ts +6 -1
- package/front_end/core/sdk/NetworkManager.ts +4 -3
- package/front_end/devtools_compatibility.js +0 -36
- package/front_end/entrypoints/lighthouse_worker/LighthouseService.ts +84 -13
- package/front_end/entrypoints/main/MainImpl.ts +4 -0
- package/front_end/models/issues_manager/FederatedAuthRequestIssue.ts +265 -0
- package/front_end/models/issues_manager/IssuesManager.ts +5 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestAccountsHttpNotFound.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestAccountsInvalidResponse.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestAccountsNoResponse.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestApprovalDeclined.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestCanceled.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestClientIdMetadataHttpNotFound.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestClientIdMetadataInvalidResponse.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestClientIdMetadataNoResponse.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestErrorFetchingSignin.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestErrorIdToken.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestIdTokenHttpNotFound.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestIdTokenInvalidRequest.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestIdTokenInvalidResponse.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestIdTokenNoResponse.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestInvalidSigninResponse.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestTooManyRequests.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestWellKnownHttpNotFound.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestWellKnownInvalidResponse.md +1 -0
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestWellKnownNoResponse.md +1 -0
- package/front_end/models/persistence/NetworkPersistenceManager.ts +205 -41
- package/front_end/models/timeline_model/TimelineFrameModel.ts +21 -7
- package/front_end/panels/application/InterestGroupStorageView.ts +21 -7
- package/front_end/panels/application/components/ReportsGrid.ts +19 -4
- package/front_end/panels/console/ConsoleViewMessage.ts +3 -5
- package/front_end/panels/console/ErrorStackParser.ts +5 -3
- package/front_end/panels/lighthouse/LighthouseController.ts +25 -1
- package/front_end/panels/lighthouse/LighthouseProtocolService.ts +37 -5
- package/front_end/panels/lighthouse/LighthouseReportRenderer.ts +6 -3
- package/front_end/panels/lighthouse/LighthouseStartView.ts +1 -0
- package/front_end/panels/lighthouse/LighthouseStatusView.ts +5 -5
- package/front_end/panels/sources/CSSPlugin.ts +2 -0
- package/front_end/panels/sources/DebuggerPlugin.ts +1 -1
- package/front_end/panels/sources/ScopeChainSidebarPane.ts +31 -0
- package/front_end/panels/sources/SourceMapNamesResolver.ts +15 -9
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +75 -3
- package/front_end/services/puppeteer/PuppeteerConnection.ts +107 -0
- package/front_end/services/puppeteer/puppeteer.ts +9 -0
- package/front_end/third_party/codemirror.next/README.chromium +10 -0
- package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/cpp.js +2 -1
- package/front_end/third_party/codemirror.next/chunk/markdown.js +2 -2
- package/front_end/third_party/codemirror.next/chunk/python.js +2 -1
- package/front_end/third_party/codemirror.next/codemirror.next.d.ts +574 -553
- package/front_end/third_party/codemirror.next/package.json +11 -11
- package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +2 -2
- package/front_end/ui/legacy/components/object_ui/ObjectPopoverHelper.ts +13 -34
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +1 -1
- package/front_end/ui/legacy/components/object_ui/objectPopover.css +0 -25
- package/front_end/ui/legacy/components/perf_ui/TimelineOverviewPane.ts +2 -2
- package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +4 -2
- package/package.json +2 -2
- package/scripts/build/devtools_plugin.js +32 -1
- package/scripts/build/esbuild.js +1 -24
- package/scripts/build/tests/plugins_test.js +60 -1
- package/scripts/devtools_paths.js +1 -29
- package/scripts/hosted_mode/server.js +5 -0
@@ -138,10 +138,10 @@ export class TimelineFrameModel {
|
|
138
138
|
}
|
139
139
|
this.lastBeginFrame = startTime;
|
140
140
|
|
141
|
-
this.beginFrameQueue.addFrameIfNotExists(seqId, startTime, false);
|
141
|
+
this.beginFrameQueue.addFrameIfNotExists(seqId, startTime, false, false);
|
142
142
|
}
|
143
143
|
|
144
|
-
handleDroppedFrame(startTime: number, seqId: number): void {
|
144
|
+
handleDroppedFrame(startTime: number, seqId: number, isPartial: boolean): void {
|
145
145
|
if (!this.lastFrame) {
|
146
146
|
this.startFrame(startTime);
|
147
147
|
}
|
@@ -149,8 +149,9 @@ export class TimelineFrameModel {
|
|
149
149
|
// This line handles the case where no BeginFrame event is issued for
|
150
150
|
// the dropped frame. In this situation, add a BeginFrame to the queue
|
151
151
|
// as if it actually occurred.
|
152
|
-
this.beginFrameQueue.addFrameIfNotExists(seqId, startTime, true);
|
152
|
+
this.beginFrameQueue.addFrameIfNotExists(seqId, startTime, true, isPartial);
|
153
153
|
this.beginFrameQueue.setDropped(seqId, true);
|
154
|
+
this.beginFrameQueue.setPartial(seqId, isPartial);
|
154
155
|
}
|
155
156
|
|
156
157
|
handleDrawFrame(startTime: number, seqId: number): void {
|
@@ -187,6 +188,9 @@ export class TimelineFrameModel {
|
|
187
188
|
if (frame.isDropped) {
|
188
189
|
this.lastFrame.dropped = true;
|
189
190
|
}
|
191
|
+
if (frame.isPartial) {
|
192
|
+
this.lastFrame.isPartial = true;
|
193
|
+
}
|
190
194
|
}
|
191
195
|
}
|
192
196
|
this.mainFrameCommitted = false;
|
@@ -318,7 +322,7 @@ export class TimelineFrameModel {
|
|
318
322
|
} else if (event.name === RecordType.NeedsBeginFrameChanged) {
|
319
323
|
this.handleNeedFrameChanged(timestamp, event.args['data'] && event.args['data']['needsBeginFrame']);
|
320
324
|
} else if (event.name === RecordType.DroppedFrame) {
|
321
|
-
this.handleDroppedFrame(timestamp, event.args['frameSeqId']);
|
325
|
+
this.handleDroppedFrame(timestamp, event.args['frameSeqId'], event.args['hasPartialUpdate']);
|
322
326
|
}
|
323
327
|
}
|
324
328
|
|
@@ -426,6 +430,7 @@ export class TimelineFrame {
|
|
426
430
|
cpuTime: number;
|
427
431
|
idle: boolean;
|
428
432
|
dropped: boolean;
|
433
|
+
isPartial: boolean;
|
429
434
|
layerTree: TracingFrameLayerTree|null;
|
430
435
|
paints: LayerPaintEvent[];
|
431
436
|
mainFrameId: number|undefined;
|
@@ -439,6 +444,7 @@ export class TimelineFrame {
|
|
439
444
|
this.cpuTime = 0;
|
440
445
|
this.idle = false;
|
441
446
|
this.dropped = false;
|
447
|
+
this.isPartial = false;
|
442
448
|
this.layerTree = null;
|
443
449
|
this.paints = [];
|
444
450
|
this.mainFrameId = undefined;
|
@@ -545,10 +551,12 @@ class BeginFrameInfo {
|
|
545
551
|
seqId: number;
|
546
552
|
startTime: number;
|
547
553
|
isDropped: boolean;
|
548
|
-
|
554
|
+
isPartial: boolean;
|
555
|
+
constructor(seqId: number, startTime: number, isDropped: boolean, isPartial: boolean) {
|
549
556
|
this.seqId = seqId;
|
550
557
|
this.startTime = startTime;
|
551
558
|
this.isDropped = isDropped;
|
559
|
+
this.isPartial = isPartial;
|
552
560
|
}
|
553
561
|
}
|
554
562
|
|
@@ -570,9 +578,9 @@ export class TimelineFrameBeginFrameQueue {
|
|
570
578
|
}
|
571
579
|
|
572
580
|
// Add a BeginFrame to the queue, if it does not already exit.
|
573
|
-
addFrameIfNotExists(seqId: number, startTime: number, isDropped: boolean): void {
|
581
|
+
addFrameIfNotExists(seqId: number, startTime: number, isDropped: boolean, isPartial: boolean): void {
|
574
582
|
if (!(seqId in this.mapFrames)) {
|
575
|
-
this.mapFrames[seqId] = new BeginFrameInfo(seqId, startTime, isDropped);
|
583
|
+
this.mapFrames[seqId] = new BeginFrameInfo(seqId, startTime, isDropped, isPartial);
|
576
584
|
this.queueFrames.push(seqId);
|
577
585
|
}
|
578
586
|
}
|
@@ -584,6 +592,12 @@ export class TimelineFrameBeginFrameQueue {
|
|
584
592
|
}
|
585
593
|
}
|
586
594
|
|
595
|
+
setPartial(seqId: number, isPartial: boolean): void {
|
596
|
+
if (seqId in this.mapFrames) {
|
597
|
+
this.mapFrames[seqId].isPartial = isPartial;
|
598
|
+
}
|
599
|
+
}
|
600
|
+
|
587
601
|
processPendingBeginFramesOnDrawFrame(seqId: number): BeginFrameInfo[] {
|
588
602
|
const framesToVisualize: BeginFrameInfo[] = [];
|
589
603
|
|
@@ -18,8 +18,10 @@ const UIStrings = {
|
|
18
18
|
*/
|
19
19
|
clickToDisplayBody: 'Click on any interest group event to display the group\'s current state',
|
20
20
|
/**
|
21
|
-
|
21
|
+
*@description Placeholder text telling the user no details are available for
|
22
|
+
*the selected interest group.
|
22
23
|
*/
|
24
|
+
noDataAvailable: 'No details available for the selected interest group. The browser may have left the group.',
|
23
25
|
};
|
24
26
|
const str_ = i18n.i18n.registerUIStrings('panels/application/InterestGroupStorageView.ts', UIStrings);
|
25
27
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
@@ -37,24 +39,33 @@ export class InterestGroupStorageView extends UI.SplitWidget.SplitWidget {
|
|
37
39
|
private readonly interestGroupGrid = new ApplicationComponents.InterestGroupAccessGrid.InterestGroupAccessGrid();
|
38
40
|
private events: Protocol.Storage.InterestGroupAccessedEvent[] = [];
|
39
41
|
private detailsGetter: InterestGroupDetailsGetter;
|
42
|
+
private noDataView: UI.Widget.VBox;
|
43
|
+
private noDisplayView: UI.Widget.VBox;
|
40
44
|
|
41
45
|
constructor(detailsGetter: InterestGroupDetailsGetter) {
|
42
46
|
super(/* isVertical */ false, /* secondIsSidebar: */ true);
|
43
47
|
this.detailsGetter = detailsGetter;
|
44
48
|
|
45
49
|
const topPanel = new UI.Widget.VBox();
|
46
|
-
|
50
|
+
this.noDisplayView = new UI.Widget.VBox();
|
51
|
+
this.noDataView = new UI.Widget.VBox();
|
52
|
+
|
47
53
|
topPanel.setMinimumSize(0, 80);
|
48
54
|
this.setMainWidget(topPanel);
|
49
|
-
|
50
|
-
this.setSidebarWidget(
|
55
|
+
this.noDisplayView.setMinimumSize(0, 40);
|
56
|
+
this.setSidebarWidget(this.noDisplayView);
|
57
|
+
this.noDataView.setMinimumSize(0, 40);
|
51
58
|
|
52
59
|
topPanel.contentElement.appendChild(this.interestGroupGrid);
|
53
60
|
this.interestGroupGrid.addEventListener('cellfocused', this.onFocus.bind(this));
|
54
61
|
|
55
|
-
|
56
|
-
const
|
57
|
-
|
62
|
+
this.noDisplayView.contentElement.classList.add('placeholder');
|
63
|
+
const noDisplayDiv = this.noDisplayView.contentElement.createChild('div');
|
64
|
+
noDisplayDiv.textContent = i18nString(UIStrings.clickToDisplayBody);
|
65
|
+
|
66
|
+
this.noDataView.contentElement.classList.add('placeholder');
|
67
|
+
const noDataDiv = this.noDataView.contentElement.createChild('div');
|
68
|
+
noDataDiv.textContent = i18nString(UIStrings.noDataAvailable);
|
58
69
|
}
|
59
70
|
|
60
71
|
wasShown(): void {
|
@@ -77,6 +88,7 @@ export class InterestGroupStorageView extends UI.SplitWidget.SplitWidget {
|
|
77
88
|
clearEvents(): void {
|
78
89
|
this.events = [];
|
79
90
|
this.interestGroupGrid.data = this.events;
|
91
|
+
this.setSidebarWidget(this.noDisplayView);
|
80
92
|
}
|
81
93
|
|
82
94
|
private async onFocus(event: Event): Promise<void> {
|
@@ -99,6 +111,8 @@ export class InterestGroupStorageView extends UI.SplitWidget.SplitWidget {
|
|
99
111
|
if (jsonView) {
|
100
112
|
this.setSidebarWidget(jsonView);
|
101
113
|
}
|
114
|
+
} else {
|
115
|
+
this.setSidebarWidget(this.noDataView);
|
102
116
|
}
|
103
117
|
}
|
104
118
|
|
@@ -19,6 +19,21 @@ const UIStrings = {
|
|
19
19
|
*(https://developers.google.com/web/updates/2018/09/reportingapi#sending)
|
20
20
|
*/
|
21
21
|
noReportsToDisplay: 'No reports to display',
|
22
|
+
/**
|
23
|
+
*@description Column header for a table displaying Reporting API reports.
|
24
|
+
*Status is one of 'Queued', 'Pending', 'MarkedForRemoval' or 'Success'.
|
25
|
+
*/
|
26
|
+
status: 'Status',
|
27
|
+
/**
|
28
|
+
*@description Column header for a table displaying Reporting API reports.
|
29
|
+
*Destination is the name of the endpoint the report is being sent to.
|
30
|
+
*/
|
31
|
+
destination: 'Destination',
|
32
|
+
/**
|
33
|
+
*@description Column header for a table displaying Reporting API reports.
|
34
|
+
*The column contains the timestamp of when a report was generated.
|
35
|
+
*/
|
36
|
+
generatedAt: 'Generated at',
|
22
37
|
};
|
23
38
|
const str_ = i18n.i18n.registerUIStrings('panels/application/components/ReportsGrid.ts', UIStrings);
|
24
39
|
export const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
@@ -38,7 +53,7 @@ export class ReportsGridStatusHeader extends HTMLElement {
|
|
38
53
|
// Disabled until https://crbug.com/1079231 is fixed.
|
39
54
|
// clang-format off
|
40
55
|
render(html`
|
41
|
-
${
|
56
|
+
${i18nString(UIStrings.status)}
|
42
57
|
<x-link href="https://web.dev/reporting-api/#report-status">
|
43
58
|
<${IconButton.Icon.Icon.litTagName} class="inline-icon" .data=${{
|
44
59
|
iconName: 'help_outline',
|
@@ -93,7 +108,7 @@ export class ReportsGrid extends HTMLElement {
|
|
93
108
|
},
|
94
109
|
{
|
95
110
|
id: 'status',
|
96
|
-
title:
|
111
|
+
title: i18nString(UIStrings.status),
|
97
112
|
widthWeighting: 20,
|
98
113
|
hideable: false,
|
99
114
|
visible: true,
|
@@ -103,14 +118,14 @@ export class ReportsGrid extends HTMLElement {
|
|
103
118
|
},
|
104
119
|
{
|
105
120
|
id: 'destination',
|
106
|
-
title:
|
121
|
+
title: i18nString(UIStrings.destination),
|
107
122
|
widthWeighting: 20,
|
108
123
|
hideable: false,
|
109
124
|
visible: true,
|
110
125
|
},
|
111
126
|
{
|
112
127
|
id: 'timestamp',
|
113
|
-
title:
|
128
|
+
title: i18nString(UIStrings.generatedAt),
|
114
129
|
widthWeighting: 20,
|
115
130
|
hideable: false,
|
116
131
|
visible: true,
|
@@ -1470,10 +1470,8 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
|
|
1470
1470
|
continue;
|
1471
1471
|
}
|
1472
1472
|
const formattedLine = document.createElement('span');
|
1473
|
-
const
|
1474
|
-
|
1475
|
-
|
1476
|
-
formattedLine.appendChild(this.linkifyStringAsFragment(prefix));
|
1473
|
+
const suffix = `${link.suffix}${newline}`;
|
1474
|
+
formattedLine.appendChild(this.linkifyStringAsFragment(link.prefix));
|
1477
1475
|
const scriptLocationLink = this.linkifier.linkifyScriptLocation(
|
1478
1476
|
debuggerModel.target(), link.scriptId || null, link.url, link.lineNumber, {
|
1479
1477
|
columnNumber: link.columnNumber,
|
@@ -1492,7 +1490,7 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
|
|
1492
1490
|
continue;
|
1493
1491
|
}
|
1494
1492
|
|
1495
|
-
const prefixWithoutFunction = prefix.substring(0, prefix.lastIndexOf(' ', prefix.length - 3));
|
1493
|
+
const prefixWithoutFunction = link.prefix.substring(0, link.prefix.lastIndexOf(' ', link.prefix.length - 3));
|
1496
1494
|
|
1497
1495
|
// If we were able to parse the function name from the stack trace line, try to replace it with an expansion of
|
1498
1496
|
// any inline frames.
|
@@ -10,8 +10,10 @@ export interface ParsedErrorFrame {
|
|
10
10
|
line: string;
|
11
11
|
link?: {
|
12
12
|
url: string,
|
13
|
+
prefix: string,
|
14
|
+
suffix: string,
|
13
15
|
lineNumber?: number,
|
14
|
-
columnNumber?: number, enclosedInBraces: boolean,
|
16
|
+
columnNumber?: number, enclosedInBraces: boolean,
|
15
17
|
scriptId?: Protocol.Runtime.ScriptId,
|
16
18
|
};
|
17
19
|
}
|
@@ -88,9 +90,9 @@ export function parseSourcePositionsFromErrorStack(
|
|
88
90
|
line,
|
89
91
|
link: {
|
90
92
|
url,
|
93
|
+
prefix: line.substring(0, left),
|
94
|
+
suffix: line.substring(right),
|
91
95
|
enclosedInBraces: hasOpenBracket,
|
92
|
-
positionLeft: left,
|
93
|
-
positionRight: right,
|
94
96
|
lineNumber: splitResult.lineNumber,
|
95
97
|
columnNumber: splitResult.columnNumber,
|
96
98
|
},
|
@@ -125,6 +125,14 @@ const UIStrings = {
|
|
125
125
|
*@description Text of checkbox to reset storage features prior to running audits in Lighthouse
|
126
126
|
*/
|
127
127
|
clearStorage: 'Clear storage',
|
128
|
+
/**
|
129
|
+
* @description Text of checkbox to use the legacy Lighthouse navigation mode
|
130
|
+
*/
|
131
|
+
legacyNavigation: 'Legacy navigation',
|
132
|
+
/**
|
133
|
+
* @description Tooltip text that appears when hovering over the 'Legacy navigation' checkbox in the settings pane opened by clicking the setting cog in the start view of the audits panel
|
134
|
+
*/
|
135
|
+
useLegacyNavigation: 'Audit the page using classic Lighthouse when in navigation mode.',
|
128
136
|
/**
|
129
137
|
* @description Tooltip text of checkbox to reset storage features prior to running audits in
|
130
138
|
* Lighthouse. Resetting the storage clears/empties it to a neutral state.
|
@@ -277,7 +285,11 @@ export class LighthouseController extends Common.ObjectWrapper.ObjectWrapper<Eve
|
|
277
285
|
return navigationEntry.url;
|
278
286
|
}
|
279
287
|
|
280
|
-
getFlags(): {
|
288
|
+
getFlags(): {
|
289
|
+
internalDisableDeviceScreenEmulation: boolean,
|
290
|
+
emulatedFormFactor: (string|undefined),
|
291
|
+
legacyNavigation: boolean,
|
292
|
+
} {
|
281
293
|
const flags = {
|
282
294
|
// DevTools handles all the emulation. This tells Lighthouse to not bother with emulation.
|
283
295
|
internalDisableDeviceScreenEmulation: true,
|
@@ -288,6 +300,7 @@ export class LighthouseController extends Common.ObjectWrapper.ObjectWrapper<Eve
|
|
288
300
|
return flags as {
|
289
301
|
internalDisableDeviceScreenEmulation: boolean,
|
290
302
|
emulatedFormFactor: (string | undefined),
|
303
|
+
legacyNavigation: boolean,
|
291
304
|
};
|
292
305
|
}
|
293
306
|
|
@@ -433,6 +446,17 @@ export const RuntimeSettings: RuntimeSetting[] = [
|
|
433
446
|
options: undefined,
|
434
447
|
learnMore: undefined,
|
435
448
|
},
|
449
|
+
{
|
450
|
+
setting: Common.Settings.Settings.instance().createSetting(
|
451
|
+
'lighthouse.legacy_navigation', true, Common.Settings.SettingStorageType.Synced),
|
452
|
+
title: i18nLazyString(UIStrings.legacyNavigation),
|
453
|
+
description: i18nLazyString(UIStrings.useLegacyNavigation),
|
454
|
+
setFlags: (flags: Flags, value: string|boolean): void => {
|
455
|
+
flags.legacyNavigation = value;
|
456
|
+
},
|
457
|
+
options: undefined,
|
458
|
+
learnMore: undefined,
|
459
|
+
},
|
436
460
|
];
|
437
461
|
|
438
462
|
// TODO(crbug.com/1167717): Make this a const enum again
|
@@ -11,6 +11,11 @@ import type * as ReportRenderer from './LighthouseReporterTypes.js';
|
|
11
11
|
let lastId = 1;
|
12
12
|
|
13
13
|
export class ProtocolService {
|
14
|
+
private targetInfo?: {
|
15
|
+
mainSessionId: string,
|
16
|
+
mainTargetId: string,
|
17
|
+
mainFrameId: string,
|
18
|
+
};
|
14
19
|
private rawConnection?: ProtocolClient.InspectorBackend.Connection;
|
15
20
|
private lighthouseWorkerPromise?: Promise<Worker>;
|
16
21
|
private lighthouseMessageUpdateCallback?: ((arg0: string) => void);
|
@@ -19,26 +24,53 @@ export class ProtocolService {
|
|
19
24
|
await SDK.TargetManager.TargetManager.instance().suspendAllTargets();
|
20
25
|
const mainTarget = SDK.TargetManager.TargetManager.instance().mainTarget();
|
21
26
|
if (!mainTarget) {
|
22
|
-
throw new Error('Unable to find main target required for
|
27
|
+
throw new Error('Unable to find main target required for Lighthouse');
|
23
28
|
}
|
24
29
|
const childTargetManager = mainTarget.model(SDK.ChildTargetManager.ChildTargetManager);
|
25
30
|
if (!childTargetManager) {
|
26
|
-
throw new Error('Unable to find child target manager required for
|
31
|
+
throw new Error('Unable to find child target manager required for Lighthouse');
|
27
32
|
}
|
28
|
-
|
33
|
+
const resourceTreeModel = mainTarget.model(SDK.ResourceTreeModel.ResourceTreeModel);
|
34
|
+
if (!resourceTreeModel) {
|
35
|
+
throw new Error('Unable to find resource tree model required for Lighthouse');
|
36
|
+
}
|
37
|
+
const mainFrame = resourceTreeModel.mainFrame;
|
38
|
+
if (!mainFrame) {
|
39
|
+
throw new Error('Unable to find main frame required for Lighthouse');
|
40
|
+
}
|
41
|
+
|
42
|
+
const {connection, sessionId} = await childTargetManager.createParallelConnection(message => {
|
29
43
|
if (typeof message === 'string') {
|
30
44
|
message = JSON.parse(message);
|
31
45
|
}
|
32
46
|
this.dispatchProtocolMessage(message);
|
33
47
|
});
|
48
|
+
|
49
|
+
this.rawConnection = connection;
|
50
|
+
this.targetInfo = {
|
51
|
+
mainTargetId: await childTargetManager.getParentTargetId(),
|
52
|
+
mainFrameId: mainFrame.id,
|
53
|
+
mainSessionId: sessionId,
|
54
|
+
};
|
34
55
|
}
|
35
56
|
|
36
57
|
getLocales(): readonly string[] {
|
37
58
|
return [i18n.DevToolsLocale.DevToolsLocale.instance().locale];
|
38
59
|
}
|
39
60
|
|
40
|
-
startLighthouse(auditURL: string, categoryIDs: string[], flags: Object):
|
41
|
-
|
61
|
+
async startLighthouse(auditURL: string, categoryIDs: string[], flags: Record<string, Object|undefined>):
|
62
|
+
Promise<ReportRenderer.RunnerResult> {
|
63
|
+
if (!this.targetInfo) {
|
64
|
+
throw new Error('Unable to get target info required for Lighthouse');
|
65
|
+
}
|
66
|
+
const mode = flags.legacyNavigation ? 'start' : 'navigate';
|
67
|
+
return this.sendWithResponse(mode, {
|
68
|
+
url: auditURL,
|
69
|
+
categoryIDs,
|
70
|
+
flags,
|
71
|
+
locales: this.getLocales(),
|
72
|
+
target: this.targetInfo,
|
73
|
+
});
|
42
74
|
}
|
43
75
|
|
44
76
|
async detach(): Promise<void> {
|
@@ -140,9 +140,12 @@ export class LighthouseReportRenderer extends LighthouseReport.ReportRenderer {
|
|
140
140
|
}
|
141
141
|
|
142
142
|
static handleDarkMode(el: Element): void {
|
143
|
-
|
144
|
-
el.classList.
|
145
|
-
}
|
143
|
+
const updateDarkModeIfNecessary = (): void => {
|
144
|
+
el.classList.toggle('lh-dark', ThemeSupport.ThemeSupport.instance().themeName() === 'dark');
|
145
|
+
};
|
146
|
+
ThemeSupport.ThemeSupport.instance().addEventListener(
|
147
|
+
ThemeSupport.ThemeChangeEvent.eventName, updateDarkModeIfNecessary);
|
148
|
+
updateDarkModeIfNecessary();
|
146
149
|
}
|
147
150
|
}
|
148
151
|
|
@@ -113,6 +113,7 @@ export class StartView extends UI.Widget.Widget {
|
|
113
113
|
}
|
114
114
|
|
115
115
|
private render(): void {
|
116
|
+
this.populateRuntimeSettingAsToolbarCheckbox('lighthouse.legacy_navigation', this.settingsToolbarInternal);
|
116
117
|
this.populateRuntimeSettingAsToolbarCheckbox('lighthouse.clear_storage', this.settingsToolbarInternal);
|
117
118
|
this.populateRuntimeSettingAsToolbarCheckbox('lighthouse.throttling', this.settingsToolbarInternal);
|
118
119
|
|
@@ -321,7 +321,7 @@ export class StatusView {
|
|
321
321
|
}
|
322
322
|
|
323
323
|
private getPhaseForMessage(message: string): StatusPhase|null {
|
324
|
-
return StatusPhases.find(phase =>
|
324
|
+
return StatusPhases.find(phase => phase.statusMessageRegex.test(message)) || null;
|
325
325
|
}
|
326
326
|
|
327
327
|
private resetProgressBarClasses(): void {
|
@@ -457,7 +457,7 @@ export interface StatusPhase {
|
|
457
457
|
id: string;
|
458
458
|
progressBarClass: string;
|
459
459
|
message: () => Common.UIString.LocalizedString;
|
460
|
-
|
460
|
+
statusMessageRegex: RegExp;
|
461
461
|
}
|
462
462
|
|
463
463
|
export const StatusPhases: StatusPhase[] = [
|
@@ -465,19 +465,19 @@ export const StatusPhases: StatusPhase[] = [
|
|
465
465
|
id: 'loading',
|
466
466
|
progressBarClass: 'loading',
|
467
467
|
message: i18nLazyString(UIStrings.lighthouseIsLoadingThePage),
|
468
|
-
|
468
|
+
statusMessageRegex: /^(Loading page|Navigating to)/,
|
469
469
|
},
|
470
470
|
{
|
471
471
|
id: 'gathering',
|
472
472
|
progressBarClass: 'gathering',
|
473
473
|
message: i18nLazyString(UIStrings.lighthouseIsGatheringInformation),
|
474
|
-
|
474
|
+
statusMessageRegex: /^(Gathering|Computing artifact)/,
|
475
475
|
},
|
476
476
|
{
|
477
477
|
id: 'auditing',
|
478
478
|
progressBarClass: 'auditing',
|
479
479
|
message: i18nLazyString(UIStrings.almostThereLighthouseIsNow),
|
480
|
-
|
480
|
+
statusMessageRegex: /^Auditing/,
|
481
481
|
},
|
482
482
|
];
|
483
483
|
|
@@ -238,12 +238,14 @@ function createCSSTooltip(active: ActiveTooltip): CodeMirror.Tooltip {
|
|
238
238
|
changes: text === active.text ? undefined :
|
239
239
|
{from: active.pos, to: active.pos + text.length, insert: active.text},
|
240
240
|
});
|
241
|
+
widget.hideWidget();
|
241
242
|
view.focus();
|
242
243
|
}
|
243
244
|
});
|
244
245
|
widget.element.addEventListener('focusout', event => {
|
245
246
|
if (event.relatedTarget && !widget.element.contains(event.relatedTarget as Node)) {
|
246
247
|
view.dispatch({effects: setTooltip.of(null)});
|
248
|
+
widget.hideWidget();
|
247
249
|
}
|
248
250
|
}, false);
|
249
251
|
widget.element.addEventListener('mousedown', event => event.consume());
|
@@ -607,7 +607,7 @@ export class DebuggerPlugin extends Plugin {
|
|
607
607
|
return null;
|
608
608
|
}
|
609
609
|
while (
|
610
|
-
node && node.name !== 'VariableDefinition' && node.name !== 'VariableName' &&
|
610
|
+
node && node.name !== 'this' && node.name !== 'VariableDefinition' && node.name !== 'VariableName' &&
|
611
611
|
node.name !== 'MemberExpression' &&
|
612
612
|
!(node.name === 'PropertyName' && node.parent?.name === 'PatternProperty' &&
|
613
613
|
node.nextSibling?.name !== ':') &&
|
@@ -90,6 +90,8 @@ export class ScopeChainSidebarPane extends UI.Widget.VBox implements UI.ContextF
|
|
90
90
|
private readonly expandController: ObjectUI.ObjectPropertiesSection.ObjectPropertiesSectionsTreeExpandController;
|
91
91
|
private readonly linkifier: Components.Linkifier.Linkifier;
|
92
92
|
private infoElement: HTMLDivElement;
|
93
|
+
#scopesScript: SDK.Script.Script|null = null;
|
94
|
+
|
93
95
|
private constructor() {
|
94
96
|
super(true);
|
95
97
|
|
@@ -126,6 +128,34 @@ export class ScopeChainSidebarPane extends UI.Widget.VBox implements UI.ContextF
|
|
126
128
|
}
|
127
129
|
}
|
128
130
|
|
131
|
+
private sourceMapAttached(
|
132
|
+
event: Common.EventTarget.EventTargetEvent<{client: SDK.Script.Script, sourceMap: SDK.SourceMap.SourceMap}>):
|
133
|
+
void {
|
134
|
+
if (event.data.client === this.#scopesScript) {
|
135
|
+
void this.update();
|
136
|
+
}
|
137
|
+
}
|
138
|
+
|
139
|
+
private setScopeSourceMapSubscription(callFrame: SDK.DebuggerModel.CallFrame|null): void {
|
140
|
+
const oldScript = this.#scopesScript;
|
141
|
+
this.#scopesScript = callFrame?.script ?? null;
|
142
|
+
|
143
|
+
// Shortcut for the case when we are listening to the same model.
|
144
|
+
if (oldScript?.debuggerModel === this.#scopesScript?.debuggerModel) {
|
145
|
+
return;
|
146
|
+
}
|
147
|
+
|
148
|
+
if (oldScript) {
|
149
|
+
oldScript.debuggerModel.sourceMapManager().removeEventListener(
|
150
|
+
SDK.SourceMapManager.Events.SourceMapAttached, this.sourceMapAttached, this);
|
151
|
+
}
|
152
|
+
|
153
|
+
if (this.#scopesScript) {
|
154
|
+
this.#scopesScript.debuggerModel.sourceMapManager().addEventListener(
|
155
|
+
SDK.SourceMapManager.Events.SourceMapAttached, this.sourceMapAttached, this);
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
129
159
|
private async update(): Promise<void> {
|
130
160
|
// The `resolveThisObject(callFrame)` and `resolveScopeChain(callFrame)` calls
|
131
161
|
// below may take a while to complete, so indicate to the user that something
|
@@ -137,6 +167,7 @@ export class ScopeChainSidebarPane extends UI.Widget.VBox implements UI.ContextF
|
|
137
167
|
this.linkifier.reset();
|
138
168
|
|
139
169
|
const callFrame = UI.Context.Context.instance().flavor(SDK.DebuggerModel.CallFrame);
|
170
|
+
this.setScopeSourceMapSubscription(callFrame);
|
140
171
|
const [thisObject, scopeChain] = await Promise.all([resolveThisObject(callFrame), resolveScopeChain(callFrame)]);
|
141
172
|
// By now the developer might have moved on, and we don't want to show stale
|
142
173
|
// scope information, so check again that we're still on the same CallFrame.
|
@@ -10,9 +10,14 @@ import * as TextUtils from '../../models/text_utils/text_utils.js';
|
|
10
10
|
import type * as Workspace from '../../models/workspace/workspace.js';
|
11
11
|
import * as Protocol from '../../generated/protocol.js';
|
12
12
|
|
13
|
-
|
13
|
+
interface CachedScopeMap {
|
14
|
+
sourceMap: SDK.SourceMap.SourceMap|null;
|
15
|
+
identifiersPromise: Promise<Map<string, string>>;
|
16
|
+
}
|
14
17
|
|
18
|
+
const scopeToCachedIdentifiersMap = new WeakMap<SDK.DebuggerModel.ScopeChainEntry, CachedScopeMap>();
|
15
19
|
const cachedMapByCallFrame = new WeakMap<SDK.DebuggerModel.CallFrame, Map<string, string>>();
|
20
|
+
|
16
21
|
export class Identifier {
|
17
22
|
name: string;
|
18
23
|
lineNumber: number;
|
@@ -79,17 +84,17 @@ export const resolveScopeChain =
|
|
79
84
|
};
|
80
85
|
|
81
86
|
export const resolveScope = async(scope: SDK.DebuggerModel.ScopeChainEntry): Promise<Map<string, string>> => {
|
82
|
-
let
|
83
|
-
|
87
|
+
let cachedScopeMap = scopeToCachedIdentifiersMap.get(scope);
|
88
|
+
const script = scope.callFrame().script;
|
89
|
+
const sourceMap = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().sourceMapForScript(script);
|
90
|
+
|
91
|
+
if (!cachedScopeMap || cachedScopeMap.sourceMap !== sourceMap) {
|
84
92
|
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
85
93
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
86
94
|
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
87
95
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
88
|
-
identifiersPromise = (async(): Promise<Map<any, any>> => {
|
96
|
+
const identifiersPromise = (async(): Promise<Map<any, any>> => {
|
89
97
|
const namesMapping = new Map<string, string>();
|
90
|
-
const script = scope.callFrame().script;
|
91
|
-
const sourceMap =
|
92
|
-
Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().sourceMapForScript(script);
|
93
98
|
if (sourceMap) {
|
94
99
|
const textCache = new Map<string, TextUtils.Text.Text>();
|
95
100
|
// Extract as much as possible from SourceMap and resolve
|
@@ -111,9 +116,10 @@ export const resolveScope = async(scope: SDK.DebuggerModel.ScopeChainEntry): Pro
|
|
111
116
|
}
|
112
117
|
return namesMapping;
|
113
118
|
})();
|
114
|
-
|
119
|
+
cachedScopeMap = {sourceMap, identifiersPromise};
|
120
|
+
scopeToCachedIdentifiersMap.set(scope, {sourceMap, identifiersPromise});
|
115
121
|
}
|
116
|
-
return await identifiersPromise;
|
122
|
+
return await cachedScopeMap.identifiersPromise;
|
117
123
|
|
118
124
|
async function resolveSourceName(
|
119
125
|
script: SDK.Script.Script, sourceMap: SDK.SourceMap.SourceMap, id: Identifier,
|