lighthouse 12.6.0 → 12.6.1-dev.20250603
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/core/audits/byte-efficiency/render-blocking-resources.js +1 -1
- package/core/audits/deprecations.js +1 -1
- package/core/audits/dobetterweb/doctype.js +1 -1
- package/core/audits/dobetterweb/inspector-issues.js +6 -11
- package/core/audits/insights/document-latency-insight.js +8 -1
- package/core/audits/insights/dom-size-insight.js +9 -1
- package/core/audits/insights/insight-audit.js +7 -0
- package/core/audits/insights/render-blocking-insight.js +1 -1
- package/core/audits/is-on-https.js +1 -1
- package/core/audits/third-party-cookies.js +1 -1
- package/core/computed/metrics/timing-summary.js +9 -1
- package/core/computed/page-dependency-graph.js +4 -0
- package/core/computed/trace-engine-result.js +7 -0
- package/core/config/constants.d.ts +2 -2
- package/core/config/constants.js +2 -2
- package/core/config/lr-desktop-config.js +1 -0
- package/core/config/lr-mobile-config.js +1 -0
- package/core/gather/driver/execution-context.d.ts +3 -1
- package/core/gather/driver/execution-context.js +3 -1
- package/core/gather/gatherers/css-usage.js +4 -1
- package/core/gather/gatherers/inspector-issues.d.ts +2 -2
- package/core/gather/gatherers/inspector-issues.js +31 -18
- package/core/gather/gatherers/stylesheets.js +4 -1
- package/core/lib/network-request.js +1 -0
- package/core/lib/trace-engine.d.ts +2 -0
- package/core/lib/trace-engine.js +1 -1
- package/dist/report/bundle.esm.js +14 -6
- package/dist/report/flow.js +12 -4
- package/dist/report/standalone.js +14 -6
- package/package.json +9 -9
- package/report/assets/styles.css +11 -3
- package/report/renderer/components.js +1 -1
- package/report/renderer/performance-category-renderer.js +1 -2
- package/shared/localization/locales/ar-XB.json +7 -10
- package/shared/localization/locales/ar.json +7 -10
- package/shared/localization/locales/bg.json +7 -10
- package/shared/localization/locales/ca.json +7 -10
- package/shared/localization/locales/cs.json +7 -10
- package/shared/localization/locales/da.json +7 -10
- package/shared/localization/locales/de.json +7 -10
- package/shared/localization/locales/el.json +7 -10
- package/shared/localization/locales/en-GB.json +7 -10
- package/shared/localization/locales/en-US.json +49 -7
- package/shared/localization/locales/en-XL.json +49 -7
- package/shared/localization/locales/es-419.json +7 -10
- package/shared/localization/locales/es.json +7 -10
- package/shared/localization/locales/fi.json +7 -10
- package/shared/localization/locales/fil.json +7 -10
- package/shared/localization/locales/fr.json +7 -10
- package/shared/localization/locales/he.json +7 -10
- package/shared/localization/locales/hi.json +7 -10
- package/shared/localization/locales/hr.json +7 -10
- package/shared/localization/locales/hu.json +7 -10
- package/shared/localization/locales/id.json +7 -10
- package/shared/localization/locales/it.json +7 -10
- package/shared/localization/locales/ja.json +7 -10
- package/shared/localization/locales/ko.json +7 -10
- package/shared/localization/locales/lt.json +7 -10
- package/shared/localization/locales/lv.json +7 -10
- package/shared/localization/locales/nl.json +7 -10
- package/shared/localization/locales/no.json +7 -10
- package/shared/localization/locales/pl.json +7 -10
- package/shared/localization/locales/pt-PT.json +7 -10
- package/shared/localization/locales/pt.json +7 -10
- package/shared/localization/locales/ro.json +7 -10
- package/shared/localization/locales/ru.json +7 -10
- package/shared/localization/locales/sk.json +7 -10
- package/shared/localization/locales/sl.json +7 -10
- package/shared/localization/locales/sr-Latn.json +7 -10
- package/shared/localization/locales/sr.json +7 -10
- package/shared/localization/locales/sv.json +7 -10
- package/shared/localization/locales/ta.json +7 -10
- package/shared/localization/locales/te.json +7 -10
- package/shared/localization/locales/th.json +7 -10
- package/shared/localization/locales/tr.json +7 -10
- package/shared/localization/locales/uk.json +7 -10
- package/shared/localization/locales/vi.json +7 -10
- package/shared/localization/locales/zh-HK.json +7 -10
- package/shared/localization/locales/zh-TW.json +7 -10
- package/shared/localization/locales/zh.json +7 -10
- package/shared/localization/locales.d.ts +2 -0
- package/shared/localization/locales.js +130 -139
- package/shared/tsconfig.json +2 -0
- package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +1 -0
- package/types/artifacts.d.ts +9 -26
- package/types/utility-types.d.ts +4 -0
|
@@ -291,7 +291,7 @@ class RenderBlockingResources extends Audit {
|
|
|
291
291
|
const headings = [
|
|
292
292
|
{key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
|
|
293
293
|
{key: 'totalBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnTransferSize)},
|
|
294
|
-
{key: 'wastedMs', valueType: 'timespanMs', label: str_(i18n.UIStrings.
|
|
294
|
+
{key: 'wastedMs', valueType: 'timespanMs', label: str_(i18n.UIStrings.columnDuration)},
|
|
295
295
|
];
|
|
296
296
|
|
|
297
297
|
const details = Audit.makeOpportunityDetails(headings, results,
|
|
@@ -58,7 +58,7 @@ class Deprecations extends Audit {
|
|
|
58
58
|
static async audit(artifacts, context) {
|
|
59
59
|
const bundles = await JSBundles.request(artifacts, context);
|
|
60
60
|
|
|
61
|
-
const deprecations = artifacts.InspectorIssues.deprecationIssue
|
|
61
|
+
const deprecations = (artifacts.InspectorIssues.deprecationIssue ?? [])
|
|
62
62
|
.map(deprecation => {
|
|
63
63
|
const {scriptId, url, lineNumber, columnNumber} = deprecation.sourceCodeLocation;
|
|
64
64
|
const bundle = bundles.find(bundle => bundle.script.scriptId === scriptId);
|
|
@@ -71,7 +71,7 @@ class Doctype extends Audit {
|
|
|
71
71
|
|
|
72
72
|
/** @type {LH.Crdp.Audits.QuirksModeIssueDetails[]} */
|
|
73
73
|
let quirksModeIssues = [];
|
|
74
|
-
if (trace && artifacts.InspectorIssues) {
|
|
74
|
+
if (trace && artifacts.InspectorIssues?.quirksModeIssue) {
|
|
75
75
|
const processedTrace = await ProcessedTrace.request(trace, context);
|
|
76
76
|
const mainFrameId = processedTrace.mainFrameInfo.frameId;
|
|
77
77
|
quirksModeIssues =
|
|
@@ -160,25 +160,20 @@ class IssuesPanelEntries extends Audit {
|
|
|
160
160
|
/** @type LH.Audit.Details.TableItem[] */
|
|
161
161
|
const items = [];
|
|
162
162
|
|
|
163
|
-
if (issues.mixedContentIssue
|
|
163
|
+
if (issues.mixedContentIssue?.length) {
|
|
164
164
|
items.push(this.getMixedContentRow(issues.mixedContentIssue));
|
|
165
165
|
}
|
|
166
|
-
if (issues.cookieIssue
|
|
166
|
+
if (issues.cookieIssue?.length) {
|
|
167
167
|
items.push(this.getCookieRow(issues.cookieIssue));
|
|
168
168
|
}
|
|
169
|
-
if (issues.blockedByResponseIssue
|
|
169
|
+
if (issues.blockedByResponseIssue?.length) {
|
|
170
170
|
items.push(this.getBlockedByResponseRow(issues.blockedByResponseIssue));
|
|
171
171
|
}
|
|
172
|
-
if (issues.heavyAdIssue
|
|
172
|
+
if (issues.heavyAdIssue?.length) {
|
|
173
173
|
items.push({issueType: str_(UIStrings.issueTypeHeavyAds)});
|
|
174
174
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
return issue.contentSecurityPolicyViolationType !== 'kTrustedTypesSinkViolation' &&
|
|
178
|
-
issue.contentSecurityPolicyViolationType !== 'kTrustedTypesPolicyViolation';
|
|
179
|
-
});
|
|
180
|
-
if (cspIssues.length) {
|
|
181
|
-
items.push(this.getContentSecurityPolicyRow(cspIssues));
|
|
175
|
+
if (issues.contentSecurityPolicyIssue?.length) {
|
|
176
|
+
items.push(this.getContentSecurityPolicyRow(issues.contentSecurityPolicyIssue));
|
|
182
177
|
}
|
|
183
178
|
return {
|
|
184
179
|
score: items.length > 0 ? 0 : 1,
|
|
@@ -40,7 +40,14 @@ class DocumentLatencyInsight extends Audit {
|
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
const details = Audit.makeChecklistDetails(insight.data.checklist);
|
|
44
|
+
details.debugData = {
|
|
45
|
+
type: 'debugdata',
|
|
46
|
+
redirectDuration: insight.data.redirectDuration,
|
|
47
|
+
serverResponseTime: insight.data.serverResponseTime,
|
|
48
|
+
uncompressedResponseBytes: insight.data.uncompressedResponseBytes,
|
|
49
|
+
};
|
|
50
|
+
return details;
|
|
44
51
|
});
|
|
45
52
|
}
|
|
46
53
|
}
|
|
@@ -77,7 +77,15 @@ class DOMSizeInsight extends Audit {
|
|
|
77
77
|
},
|
|
78
78
|
},
|
|
79
79
|
];
|
|
80
|
-
|
|
80
|
+
|
|
81
|
+
const details = Audit.makeTableDetails(headings, items);
|
|
82
|
+
details.debugData = {
|
|
83
|
+
type: 'debugdata',
|
|
84
|
+
totalElements,
|
|
85
|
+
maxChildren: maxChildren.numChildren,
|
|
86
|
+
maxDepth: maxDepth.depth,
|
|
87
|
+
};
|
|
88
|
+
return details;
|
|
81
89
|
});
|
|
82
90
|
}
|
|
83
91
|
}
|
|
@@ -75,6 +75,13 @@ async function adaptInsightToAuditProduct(artifacts, context, insightName, creat
|
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
if (insight.wastedBytes !== undefined) {
|
|
79
|
+
if (!details.debugData) {
|
|
80
|
+
details.debugData = {type: 'debugdata'};
|
|
81
|
+
}
|
|
82
|
+
details.debugData.wastedBytes = insight.wastedBytes;
|
|
83
|
+
}
|
|
84
|
+
|
|
78
85
|
// This hack is to add metric adorners if an insight category links it to a metric,
|
|
79
86
|
// but doesn't output a metric savings for that metric.
|
|
80
87
|
let metricSavings = insight.metricSavings;
|
|
@@ -41,7 +41,7 @@ class RenderBlockingInsight extends Audit {
|
|
|
41
41
|
const headings = [
|
|
42
42
|
{key: 'url', valueType: 'url', label: str_(i18n.UIStrings.columnURL)},
|
|
43
43
|
{key: 'totalBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnTransferSize)},
|
|
44
|
-
{key: 'wastedMs', valueType: 'timespanMs', label: str_(i18n.UIStrings.
|
|
44
|
+
{key: 'wastedMs', valueType: 'timespanMs', label: str_(i18n.UIStrings.columnDuration)},
|
|
45
45
|
];
|
|
46
46
|
/** @type {LH.Audit.Details.Table['items']} */
|
|
47
47
|
const items = insight.renderBlockingRequests.map(request => ({
|
|
@@ -86,7 +86,7 @@ class HTTPS extends Audit {
|
|
|
86
86
|
{key: 'resolution', valueType: 'text', label: str_(UIStrings.columnResolution)},
|
|
87
87
|
];
|
|
88
88
|
|
|
89
|
-
for (const details of artifacts.InspectorIssues.mixedContentIssue) {
|
|
89
|
+
for (const details of artifacts.InspectorIssues.mixedContentIssue ?? []) {
|
|
90
90
|
let item = items.find(item => item.url === details.insecureURL);
|
|
91
91
|
if (!item) {
|
|
92
92
|
item = {url: details.insecureURL};
|
|
@@ -68,7 +68,7 @@ class ThirdPartyCookies extends Audit {
|
|
|
68
68
|
|
|
69
69
|
/** @type {LH.Audit.Details.TableItem[]} */
|
|
70
70
|
const items = [];
|
|
71
|
-
for (const issue of artifacts.InspectorIssues.cookieIssue) {
|
|
71
|
+
for (const issue of artifacts.InspectorIssues.cookieIssue ?? []) {
|
|
72
72
|
const isPhaseoutWarn = issue.cookieWarningReasons.includes('WarnThirdPartyPhaseout');
|
|
73
73
|
const isPhaseoutExclude = issue.cookieExclusionReasons.includes('ExcludeThirdPartyPhaseout');
|
|
74
74
|
if (!isPhaseoutWarn && !isPhaseoutExclude) continue;
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import log from 'lighthouse-logger';
|
|
8
|
+
|
|
7
9
|
import {ProcessedTrace} from '../processed-trace.js';
|
|
8
10
|
import {ProcessedNavigation} from '../processed-navigation.js';
|
|
9
11
|
import {Speedline} from '../speedline.js';
|
|
@@ -19,6 +21,7 @@ import {TotalBlockingTime} from './total-blocking-time.js';
|
|
|
19
21
|
import {makeComputedArtifact} from '../computed-artifact.js';
|
|
20
22
|
import {TimeToFirstByte} from './time-to-first-byte.js';
|
|
21
23
|
import {LCPBreakdown} from './lcp-breakdown.js';
|
|
24
|
+
import {isUnderTest} from '../../lib/lh-env.js';
|
|
22
25
|
|
|
23
26
|
class TimingSummary {
|
|
24
27
|
/**
|
|
@@ -43,7 +46,12 @@ class TimingSummary {
|
|
|
43
46
|
* @return {Promise<TReturn|undefined>}
|
|
44
47
|
*/
|
|
45
48
|
const requestOrUndefined = (Artifact, artifact) => {
|
|
46
|
-
return Artifact.request(artifact, context).catch(
|
|
49
|
+
return Artifact.request(artifact, context).catch(err => {
|
|
50
|
+
if (isUnderTest) {
|
|
51
|
+
log.error('lh:computed:TimingSummary', err);
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
});
|
|
47
55
|
};
|
|
48
56
|
|
|
49
57
|
/* eslint-disable max-len */
|
|
@@ -36,6 +36,10 @@ class PageDependencyGraph {
|
|
|
36
36
|
return graph;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
// TODO: currently the trace version has no requests that failed, or requests that have "Preflight".
|
|
40
|
+
// so the following gets the devtools log version _closer_ to the exact same results as the trace.
|
|
41
|
+
// const lanternRequests = networkRecords.map(NetworkRequest.asLanternNetworkRequest).filter(r => !r.failed && r.resourceType !== 'Preflight');
|
|
42
|
+
|
|
39
43
|
const lanternRequests = networkRecords.map(NetworkRequest.asLanternNetworkRequest);
|
|
40
44
|
return Lantern.Graph.PageDependencyGraph.createGraph(mainThreadEvents, lanternRequests, URL);
|
|
41
45
|
}
|
|
@@ -97,6 +97,9 @@ class TraceEngineResult {
|
|
|
97
97
|
if (value && typeof value === 'object' && '__i18nBytes' in value) {
|
|
98
98
|
values[key] = value.__i18nBytes;
|
|
99
99
|
// TODO: use an actual byte formatter. Right now, this shows the exact number of bytes.
|
|
100
|
+
} else if (value && typeof value === 'object' && '__i18nMillis' in value) {
|
|
101
|
+
values[key] = `${value.__i18nMillis} ms`;
|
|
102
|
+
// TODO: use an actual time formatter.
|
|
100
103
|
} else if (value && typeof value === 'object' && 'i18nId' in value) {
|
|
101
104
|
// TODO: add support for str_ values to be IcuMessage. For now, we translate it here.
|
|
102
105
|
// This means that locale swapping won't work for this portion of the IcuMessage.
|
|
@@ -172,6 +175,10 @@ class TraceEngineResult {
|
|
|
172
175
|
// @ts-expect-error
|
|
173
176
|
values[key] = value.__i18nBytes;
|
|
174
177
|
// TODO: use an actual byte formatter. Right now, this shows the exact number of bytes.
|
|
178
|
+
} else if (value && typeof value === 'object' && '__i18nMillis' in value) {
|
|
179
|
+
// @ts-expect-error
|
|
180
|
+
values[key] = `${value.__i18nMillis} ms`;
|
|
181
|
+
// TODO: use an actual time formatter.
|
|
175
182
|
} else if (value && typeof value === 'object' && 'i18nId' in value) {
|
|
176
183
|
// TODO: add support for str_ values to be IcuMessage.
|
|
177
184
|
// @ts-expect-error
|
|
@@ -51,7 +51,7 @@ declare const MOTOGPOWER_EMULATION_METRICS: Required<LH.SharedFlagsSettings["scr
|
|
|
51
51
|
* @type {Required<LH.SharedFlagsSettings['screenEmulation']>}
|
|
52
52
|
*/
|
|
53
53
|
declare const DESKTOP_EMULATION_METRICS: Required<LH.SharedFlagsSettings["screenEmulation"]>;
|
|
54
|
-
declare const MOTOG4_USERAGENT: "Mozilla/5.0 (Linux; Android 11; moto g power (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
55
|
-
declare const DESKTOP_USERAGENT: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
54
|
+
declare const MOTOG4_USERAGENT: "Mozilla/5.0 (Linux; Android 11; moto g power (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Mobile Safari/537.36";
|
|
55
|
+
declare const DESKTOP_USERAGENT: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36";
|
|
56
56
|
export {};
|
|
57
57
|
//# sourceMappingURL=constants.d.ts.map
|
package/core/config/constants.js
CHANGED
|
@@ -39,8 +39,8 @@ const screenEmulationMetrics = {
|
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
const MOTOG4_USERAGENT = 'Mozilla/5.0 (Linux; Android 11; moto g power (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
43
|
-
const DESKTOP_USERAGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/
|
|
42
|
+
const MOTOG4_USERAGENT = 'Mozilla/5.0 (Linux; Android 11; moto g power (2022)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Mobile Safari/537.36'; // eslint-disable-line max-len
|
|
43
|
+
const DESKTOP_USERAGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36'; // eslint-disable-line max-len
|
|
44
44
|
|
|
45
45
|
const userAgents = {
|
|
46
46
|
mobile: MOTOG4_USERAGENT,
|
|
@@ -19,6 +19,7 @@ const config = {
|
|
|
19
19
|
skipAudits: [
|
|
20
20
|
// Skip the h2 audit so it doesn't lie to us. See https://github.com/GoogleChrome/lighthouse/issues/6539
|
|
21
21
|
'uses-http2',
|
|
22
|
+
'modern-http-insight',
|
|
22
23
|
// There are always bf-cache failures when testing in headless. Reenable when headless can give us realistic bf-cache insights.
|
|
23
24
|
'bf-cache',
|
|
24
25
|
],
|
|
@@ -18,6 +18,7 @@ const config = {
|
|
|
18
18
|
skipAudits: [
|
|
19
19
|
// Skip the h2 audit so it doesn't lie to us. See https://github.com/GoogleChrome/lighthouse/issues/6539
|
|
20
20
|
'uses-http2',
|
|
21
|
+
'modern-http-insight',
|
|
21
22
|
// There are always bf-cache failures when testing in headless. Reenable when headless can give us realistic bf-cache insights.
|
|
22
23
|
'bf-cache',
|
|
23
24
|
],
|
|
@@ -58,11 +58,13 @@ export class ExecutionContext {
|
|
|
58
58
|
*/
|
|
59
59
|
_evaluateInContext(expression: string, contextId: number | undefined, timeout: number): Promise<any>;
|
|
60
60
|
/**
|
|
61
|
-
* Note: Prefer `evaluate` instead.
|
|
62
61
|
* Evaluate an expression in the context of the current page. If useIsolation is true, the expression
|
|
63
62
|
* will be evaluated in a content script that has access to the page's DOM but whose JavaScript state
|
|
64
63
|
* is completely separate.
|
|
65
64
|
* Returns a promise that resolves on the expression's value.
|
|
65
|
+
*
|
|
66
|
+
* @deprecated Use `evaluate` instead! It has a better API, and unlike `evaluateAsync` doesn't sometimes
|
|
67
|
+
* execute invalid code.
|
|
66
68
|
* @param {string} expression
|
|
67
69
|
* @param {{useIsolation?: boolean}=} options
|
|
68
70
|
* @return {Promise<*>}
|
|
@@ -151,11 +151,13 @@ class ExecutionContext {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
/**
|
|
154
|
-
* Note: Prefer `evaluate` instead.
|
|
155
154
|
* Evaluate an expression in the context of the current page. If useIsolation is true, the expression
|
|
156
155
|
* will be evaluated in a content script that has access to the page's DOM but whose JavaScript state
|
|
157
156
|
* is completely separate.
|
|
158
157
|
* Returns a promise that resolves on the expression's value.
|
|
158
|
+
*
|
|
159
|
+
* @deprecated Use `evaluate` instead! It has a better API, and unlike `evaluateAsync` doesn't sometimes
|
|
160
|
+
* execute invalid code.
|
|
159
161
|
* @param {string} expression
|
|
160
162
|
* @param {{useIsolation?: boolean}=} options
|
|
161
163
|
* @return {Promise<*>}
|
|
@@ -30,7 +30,10 @@ class CSSUsage extends BaseGatherer {
|
|
|
30
30
|
|
|
31
31
|
// Force style to recompute.
|
|
32
32
|
// Doesn't appear to be necessary in newer versions of Chrome.
|
|
33
|
-
|
|
33
|
+
/* global window, document */
|
|
34
|
+
await executionContext.evaluate(() => window.getComputedStyle(document.body), {
|
|
35
|
+
args: [],
|
|
36
|
+
});
|
|
34
37
|
|
|
35
38
|
const {ruleUsage} = await session.sendCommand('CSS.stopRuleUsageTracking');
|
|
36
39
|
await session.sendCommand('CSS.disable');
|
|
@@ -19,9 +19,9 @@ declare class InspectorIssues extends BaseGatherer {
|
|
|
19
19
|
stopInstrumentation(context: LH.Gatherer.Context): Promise<void>;
|
|
20
20
|
/**
|
|
21
21
|
* @param {LH.Gatherer.Context<'DevtoolsLog'>} context
|
|
22
|
-
* @return {Promise<LH.Artifacts
|
|
22
|
+
* @return {Promise<LH.Artifacts.InspectorIssues>}
|
|
23
23
|
*/
|
|
24
|
-
getArtifact(context: LH.Gatherer.Context<"DevtoolsLog">): Promise<LH.Artifacts
|
|
24
|
+
getArtifact(context: LH.Gatherer.Context<"DevtoolsLog">): Promise<LH.Artifacts.InspectorIssues>;
|
|
25
25
|
}
|
|
26
26
|
import BaseGatherer from '../base-gatherer.js';
|
|
27
27
|
//# sourceMappingURL=inspector-issues.d.ts.map
|
|
@@ -54,7 +54,7 @@ class InspectorIssues extends BaseGatherer {
|
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* @param {LH.Gatherer.Context<'DevtoolsLog'>} context
|
|
57
|
-
* @return {Promise<LH.Artifacts
|
|
57
|
+
* @return {Promise<LH.Artifacts.InspectorIssues>}
|
|
58
58
|
*/
|
|
59
59
|
async getArtifact(context) {
|
|
60
60
|
const devtoolsLog = context.dependencies.DevtoolsLog;
|
|
@@ -62,6 +62,7 @@ class InspectorIssues extends BaseGatherer {
|
|
|
62
62
|
|
|
63
63
|
/** @type {LH.Artifacts.InspectorIssues} */
|
|
64
64
|
const artifact = {
|
|
65
|
+
// TODO(v13): remove empty arrays.
|
|
65
66
|
attributionReportingIssue: [],
|
|
66
67
|
blockedByResponseIssue: [],
|
|
67
68
|
bounceTrackingIssue: [],
|
|
@@ -86,27 +87,39 @@ class InspectorIssues extends BaseGatherer {
|
|
|
86
87
|
stylesheetLoadingIssue: [],
|
|
87
88
|
sriMessageSignatureIssue: [],
|
|
88
89
|
federatedAuthUserInfoRequestIssue: [],
|
|
90
|
+
userReidentificationIssue: [],
|
|
89
91
|
};
|
|
90
|
-
|
|
91
|
-
for (const
|
|
92
|
-
/** @type {
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
92
|
+
|
|
93
|
+
for (const issue of this._issues) {
|
|
94
|
+
const detailsKey = /** @type {keyof LH.Crdp.Audits.InspectorIssueDetails} */(
|
|
95
|
+
Object.keys(issue.details)[0]);
|
|
96
|
+
const details = issue.details[detailsKey];
|
|
97
|
+
if (!details) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const artifactKey =
|
|
102
|
+
/** @type {LH.Artifacts.InspectorIssuesKeyToArtifactKey<typeof detailsKey>} */(
|
|
103
|
+
detailsKey.replace('Details', ''));
|
|
104
|
+
|
|
105
|
+
// Duplicate issues can occur for the same request; only use the one with a matching networkRequest.
|
|
106
|
+
const requestId = 'request' in details && details.request && details.request.requestId;
|
|
107
|
+
if (requestId) {
|
|
108
|
+
if (networkRecords.find(req => req.requestId === requestId)) {
|
|
109
|
+
if (!artifact[artifactKey]) {
|
|
110
|
+
artifact[artifactKey] = [];
|
|
105
111
|
}
|
|
106
|
-
|
|
112
|
+
|
|
107
113
|
// @ts-expect-error - detail types are not all compatible
|
|
108
|
-
artifact[
|
|
114
|
+
artifact[artifactKey].push(details);
|
|
109
115
|
}
|
|
116
|
+
} else {
|
|
117
|
+
if (!artifact[artifactKey]) {
|
|
118
|
+
artifact[artifactKey] = [];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// @ts-expect-error - detail types are not all compatible
|
|
122
|
+
artifact[artifactKey].push(details);
|
|
110
123
|
}
|
|
111
124
|
}
|
|
112
125
|
|
|
@@ -74,7 +74,10 @@ class Stylesheets extends BaseGatherer {
|
|
|
74
74
|
|
|
75
75
|
// Force style to recompute.
|
|
76
76
|
// Doesn't appear to be necessary in newer versions of Chrome.
|
|
77
|
-
|
|
77
|
+
/* global window, document */
|
|
78
|
+
await executionContext.evaluate(() => window.getComputedStyle(document.body), {
|
|
79
|
+
args: [],
|
|
80
|
+
});
|
|
78
81
|
|
|
79
82
|
session.off('CSS.styleSheetAdded', this._onStylesheetAdded);
|
|
80
83
|
|
package/core/lib/trace-engine.js
CHANGED
|
@@ -4,7 +4,7 @@ import {polyfillDOMRect} from './polyfill-dom-rect.js';
|
|
|
4
4
|
|
|
5
5
|
/** @typedef {import('@paulirish/trace_engine').Types.Events.SyntheticLayoutShift} SyntheticLayoutShift */
|
|
6
6
|
/** @typedef {SyntheticLayoutShift & {args: {data: NonNullable<SyntheticLayoutShift['args']['data']>}}} SaneSyntheticLayoutShift */
|
|
7
|
-
/** @typedef {{i18nId: string, values: Record<string, string|number|{__i18nBytes: number}>}} DevToolsIcuMessage */
|
|
7
|
+
/** @typedef {{i18nId: string, values: Record<string, string|number|{__i18nBytes: number}|{__i18nMillis: number}>}} DevToolsIcuMessage */
|
|
8
8
|
|
|
9
9
|
polyfillDOMRect();
|
|
10
10
|
|