lighthouse 12.6.1-dev.20250623 → 12.6.1-dev.20250625
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/audit.d.ts +7 -0
- package/core/audits/audit.js +15 -0
- package/core/audits/insights/cache-insight.js +2 -1
- package/core/audits/insights/cls-culprits-insight.js +3 -2
- package/core/audits/insights/insight-audit.d.ts +5 -2
- package/core/audits/insights/insight-audit.js +43 -3
- package/core/audits/insights/network-dependency-tree-insight.js +85 -8
- package/core/audits/layout-shifts.js +2 -1
- package/core/config/filters.js +1 -0
- package/core/config/validation.js +4 -0
- package/core/gather/base-artifacts.js +3 -0
- package/core/gather/driver/environment.d.ts +6 -0
- package/core/gather/driver/environment.js +17 -0
- package/core/gather/gatherers/inspector-issues.js +1 -1
- package/core/lib/bf-cache-strings.js +4 -1
- package/core/lib/deprecations-strings.d.ts +51 -47
- package/core/lib/deprecations-strings.js +14 -8
- package/core/scoring.d.ts +180 -15
- package/dist/report/bundle.esm.js +9 -3
- package/dist/report/flow.js +13 -7
- package/dist/report/standalone.js +10 -4
- package/package.json +9 -9
- package/report/assets/styles.css +7 -1
- package/report/renderer/components.js +1 -1
- package/report/renderer/details-renderer.d.ts +5 -0
- package/report/renderer/details-renderer.js +35 -3
- package/report/renderer/dom.d.ts +1 -0
- package/report/renderer/dom.js +2 -0
- package/report/renderer/report-ui-features.d.ts +1 -0
- package/report/renderer/report-ui-features.js +16 -0
- package/shared/localization/locales/ar-XB.json +57 -12
- package/shared/localization/locales/ar.json +57 -12
- package/shared/localization/locales/bg.json +58 -13
- package/shared/localization/locales/ca.json +58 -13
- package/shared/localization/locales/cs.json +58 -13
- package/shared/localization/locales/da.json +58 -13
- package/shared/localization/locales/de.json +58 -13
- package/shared/localization/locales/el.json +58 -13
- package/shared/localization/locales/en-GB.json +58 -13
- package/shared/localization/locales/en-US.json +12 -12
- package/shared/localization/locales/en-XL.json +12 -12
- package/shared/localization/locales/es-419.json +58 -13
- package/shared/localization/locales/es.json +56 -11
- package/shared/localization/locales/fi.json +58 -13
- package/shared/localization/locales/fil.json +58 -13
- package/shared/localization/locales/fr.json +58 -13
- package/shared/localization/locales/he.json +58 -13
- package/shared/localization/locales/hi.json +58 -13
- package/shared/localization/locales/hr.json +58 -13
- package/shared/localization/locales/hu.json +57 -12
- package/shared/localization/locales/id.json +58 -13
- package/shared/localization/locales/it.json +57 -12
- package/shared/localization/locales/ja.json +58 -13
- package/shared/localization/locales/ko.json +58 -13
- package/shared/localization/locales/lt.json +58 -13
- package/shared/localization/locales/lv.json +57 -12
- package/shared/localization/locales/nl.json +58 -13
- package/shared/localization/locales/no.json +58 -13
- package/shared/localization/locales/pl.json +57 -12
- package/shared/localization/locales/pt-PT.json +58 -13
- package/shared/localization/locales/pt.json +58 -13
- package/shared/localization/locales/ro.json +58 -13
- package/shared/localization/locales/ru.json +59 -14
- package/shared/localization/locales/sk.json +57 -12
- package/shared/localization/locales/sl.json +57 -12
- package/shared/localization/locales/sr-Latn.json +58 -13
- package/shared/localization/locales/sr.json +58 -13
- package/shared/localization/locales/sv.json +58 -13
- package/shared/localization/locales/ta.json +58 -13
- package/shared/localization/locales/te.json +58 -13
- package/shared/localization/locales/th.json +57 -12
- package/shared/localization/locales/tr.json +58 -13
- package/shared/localization/locales/uk.json +58 -13
- package/shared/localization/locales/vi.json +58 -13
- package/shared/localization/locales/zh-HK.json +58 -13
- package/shared/localization/locales/zh-TW.json +57 -12
- package/shared/localization/locales/zh.json +58 -13
- package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +1 -1
- package/types/artifacts.d.ts +2 -0
- package/types/lhr/audit-details.d.ts +12 -3
package/core/audits/audit.d.ts
CHANGED
|
@@ -83,6 +83,13 @@ export class Audit {
|
|
|
83
83
|
* @return {LH.Audit.Details.List}
|
|
84
84
|
*/
|
|
85
85
|
static makeListDetails(items: LH.Audit.Details.List["items"]): LH.Audit.Details.List;
|
|
86
|
+
/**
|
|
87
|
+
* @param {LH.IcuMessage | string=} title
|
|
88
|
+
* @param {LH.IcuMessage | string=} description
|
|
89
|
+
* @param {LH.Audit.Details.ListableDetail} value
|
|
90
|
+
* @return {LH.Audit.Details.ListSectionItem}
|
|
91
|
+
*/
|
|
92
|
+
static makeListDetailSectionItem(value: LH.Audit.Details.ListableDetail, title?: (LH.IcuMessage | string) | undefined, description?: (LH.IcuMessage | string) | undefined): LH.Audit.Details.ListSectionItem;
|
|
86
93
|
/** @typedef {{
|
|
87
94
|
* content: string;
|
|
88
95
|
* title: string;
|
package/core/audits/audit.js
CHANGED
|
@@ -194,6 +194,21 @@ class Audit {
|
|
|
194
194
|
};
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
/**
|
|
198
|
+
* @param {LH.IcuMessage | string=} title
|
|
199
|
+
* @param {LH.IcuMessage | string=} description
|
|
200
|
+
* @param {LH.Audit.Details.ListableDetail} value
|
|
201
|
+
* @return {LH.Audit.Details.ListSectionItem}
|
|
202
|
+
*/
|
|
203
|
+
static makeListDetailSectionItem(value, title, description) {
|
|
204
|
+
return {
|
|
205
|
+
type: 'list-section',
|
|
206
|
+
title,
|
|
207
|
+
description,
|
|
208
|
+
value,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
197
212
|
/** @typedef {{
|
|
198
213
|
* content: string;
|
|
199
214
|
* title: string;
|
|
@@ -41,7 +41,7 @@ class CacheInsight extends Audit {
|
|
|
41
41
|
/* eslint-disable max-len */
|
|
42
42
|
{key: 'url', valueType: 'url', label: str_(UIStrings.requestColumn)},
|
|
43
43
|
{key: 'cacheLifetimeMs', valueType: 'ms', label: str_(UIStrings.cacheTTL), displayUnit: 'duration'},
|
|
44
|
-
{key: '
|
|
44
|
+
{key: 'totalBytes', valueType: 'bytes', label: str_(i18n.UIStrings.columnTransferSize), displayUnit: 'kb', granularity: 1},
|
|
45
45
|
/* eslint-enable max-len */
|
|
46
46
|
];
|
|
47
47
|
// TODO: this should be the sorting in the model (instead it sorts by transfer size...)
|
|
@@ -50,6 +50,7 @@ class CacheInsight extends Audit {
|
|
|
50
50
|
const items = values.map(value => ({
|
|
51
51
|
url: value.request.args.data.url,
|
|
52
52
|
cacheLifetimeMs: value.ttl * 1000,
|
|
53
|
+
totalBytes: value.request.args.data.encodedDataLength || 0,
|
|
53
54
|
wastedBytes: value.wastedBytes,
|
|
54
55
|
}));
|
|
55
56
|
return Audit.makeTableDetails(headings, items, {
|
|
@@ -59,7 +59,7 @@ class CLSCulpritsInsight extends Audit {
|
|
|
59
59
|
for (const unsizedImage of culprits.unsizedImages) {
|
|
60
60
|
subItems.push({
|
|
61
61
|
extra: makeNodeItemForNodeId(TraceElements, unsizedImage.backendNodeId),
|
|
62
|
-
cause: insightStr_(InsightUIStrings.
|
|
62
|
+
cause: insightStr_(InsightUIStrings.unsizedImage),
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
65
|
for (const request of culprits.fontRequests) {
|
|
@@ -69,8 +69,9 @@ class CLSCulpritsInsight extends Audit {
|
|
|
69
69
|
cause: insightStr_(InsightUIStrings.fontRequest),
|
|
70
70
|
});
|
|
71
71
|
}
|
|
72
|
-
|
|
72
|
+
for (const iframe of culprits.iframes) {
|
|
73
73
|
subItems.push({
|
|
74
|
+
extra: iframe.url ? {type: 'url', value: iframe.url} : undefined,
|
|
74
75
|
cause: insightStr_(InsightUIStrings.injectedIframe),
|
|
75
76
|
});
|
|
76
77
|
}
|
|
@@ -11,11 +11,14 @@ export type CreateDetailsExtras = {
|
|
|
11
11
|
* @param {LH.Artifacts} artifacts
|
|
12
12
|
* @param {LH.Audit.Context} context
|
|
13
13
|
* @param {T} insightName
|
|
14
|
-
* @param {(insight: import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModels[T], extras: CreateDetailsExtras) => LH.Audit.Details|undefined} createDetails
|
|
14
|
+
* @param {(insight: import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModels[T], extras: CreateDetailsExtras) => {details: LH.Audit.Details, warnings: Array<string | LH.IcuMessage>}|LH.Audit.Details|undefined} createDetails
|
|
15
15
|
* @template {keyof import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModelsType} T
|
|
16
16
|
* @return {Promise<LH.Audit.Product>}
|
|
17
17
|
*/
|
|
18
|
-
export function adaptInsightToAuditProduct<T extends keyof import("@paulirish/trace_engine/models/trace/insights/types.js").InsightModelsType>(artifacts: LH.Artifacts, context: LH.Audit.Context, insightName: T, createDetails: (insight: import("@paulirish/trace_engine/models/trace/insights/types.js").InsightModels[T], extras: CreateDetailsExtras) =>
|
|
18
|
+
export function adaptInsightToAuditProduct<T extends keyof import("@paulirish/trace_engine/models/trace/insights/types.js").InsightModelsType>(artifacts: LH.Artifacts, context: LH.Audit.Context, insightName: T, createDetails: (insight: import("@paulirish/trace_engine/models/trace/insights/types.js").InsightModels[T], extras: CreateDetailsExtras) => {
|
|
19
|
+
details: LH.Audit.Details;
|
|
20
|
+
warnings: Array<string | LH.IcuMessage>;
|
|
21
|
+
} | LH.Audit.Details | undefined): Promise<LH.Audit.Product>;
|
|
19
22
|
/**
|
|
20
23
|
* @param {LH.Artifacts.TraceElement[]} traceElements
|
|
21
24
|
* @param {number|null|undefined} nodeId
|
|
@@ -42,7 +42,7 @@ async function getInsightSet(artifacts, context) {
|
|
|
42
42
|
* @param {LH.Artifacts} artifacts
|
|
43
43
|
* @param {LH.Audit.Context} context
|
|
44
44
|
* @param {T} insightName
|
|
45
|
-
* @param {(insight: import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModels[T], extras: CreateDetailsExtras) => LH.Audit.Details|undefined} createDetails
|
|
45
|
+
* @param {(insight: import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModels[T], extras: CreateDetailsExtras) => {details: LH.Audit.Details, warnings: Array<string | LH.IcuMessage>}|LH.Audit.Details|undefined} createDetails
|
|
46
46
|
* @template {keyof import('@paulirish/trace_engine/models/trace/insights/types.js').InsightModelsType} T
|
|
47
47
|
* @return {Promise<LH.Audit.Product>}
|
|
48
48
|
*/
|
|
@@ -64,10 +64,21 @@ async function adaptInsightToAuditProduct(artifacts, context, insightName, creat
|
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
const
|
|
67
|
+
const cbResult = createDetails(insight, {
|
|
68
68
|
parsedTrace,
|
|
69
69
|
insights,
|
|
70
70
|
});
|
|
71
|
+
|
|
72
|
+
const warnings = [...insight.warnings ?? []];
|
|
73
|
+
|
|
74
|
+
let details;
|
|
75
|
+
if (cbResult && 'warnings' in cbResult) {
|
|
76
|
+
details = cbResult.details;
|
|
77
|
+
warnings.push(...cbResult.warnings);
|
|
78
|
+
} else {
|
|
79
|
+
details = cbResult;
|
|
80
|
+
}
|
|
81
|
+
|
|
71
82
|
if (!details || (details.type === 'table' && details.items.length === 0)) {
|
|
72
83
|
return {
|
|
73
84
|
scoreDisplayMode: Audit.SCORING_MODES.NOT_APPLICABLE,
|
|
@@ -97,8 +108,37 @@ async function adaptInsightToAuditProduct(artifacts, context, insightName, creat
|
|
|
97
108
|
// TODO: consider adding a `estimatedSavingsText` to InsightModel, which can capture
|
|
98
109
|
// the exact i18n string used by RPP; and include the same est. timing savings.
|
|
99
110
|
let displayValue;
|
|
111
|
+
|
|
100
112
|
if (insight.wastedBytes) {
|
|
101
113
|
displayValue = str_(i18n.UIStrings.displayValueByteSavings, {wastedBytes: insight.wastedBytes});
|
|
114
|
+
} else {
|
|
115
|
+
let wastedMs;
|
|
116
|
+
|
|
117
|
+
switch (insight.insightKey) {
|
|
118
|
+
case 'DocumentLatency':
|
|
119
|
+
case 'DuplicatedJavaScript':
|
|
120
|
+
case 'FontDisplay':
|
|
121
|
+
case 'LegacyJavaScript':
|
|
122
|
+
case 'RenderBlocking': {
|
|
123
|
+
wastedMs = metricSavings?.FCP;
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
case 'LCPDiscovery':
|
|
128
|
+
case 'ModernHTTP': {
|
|
129
|
+
wastedMs = metricSavings?.LCP;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
case 'Viewport': {
|
|
134
|
+
wastedMs = metricSavings?.INP;
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (wastedMs) {
|
|
140
|
+
displayValue = str_(i18n.UIStrings.displayValueMsSavings, {wastedMs});
|
|
141
|
+
}
|
|
102
142
|
}
|
|
103
143
|
|
|
104
144
|
let score;
|
|
@@ -116,7 +156,7 @@ async function adaptInsightToAuditProduct(artifacts, context, insightName, creat
|
|
|
116
156
|
scoreDisplayMode,
|
|
117
157
|
score,
|
|
118
158
|
metricSavings,
|
|
119
|
-
warnings:
|
|
159
|
+
warnings: warnings.length ? warnings : undefined,
|
|
120
160
|
displayValue,
|
|
121
161
|
details,
|
|
122
162
|
};
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {UIStrings} from '@paulirish/trace_engine/models/trace/insights/NetworkDependencyTree.js';
|
|
7
|
+
import {UIStrings, TOO_MANY_PRECONNECTS_THRESHOLD} from '@paulirish/trace_engine/models/trace/insights/NetworkDependencyTree.js';
|
|
8
8
|
|
|
9
9
|
import {Audit} from '../audit.js';
|
|
10
10
|
import * as i18n from '../../lib/i18n/i18n.js';
|
|
11
|
-
import {adaptInsightToAuditProduct} from './insight-audit.js';
|
|
11
|
+
import {adaptInsightToAuditProduct, makeNodeItemForNodeId} from './insight-audit.js';
|
|
12
12
|
|
|
13
13
|
// eslint-disable-next-line max-len
|
|
14
14
|
const str_ = i18n.createIcuMessageFn('node_modules/@paulirish/trace_engine/models/trace/insights/NetworkDependencyTree.js', UIStrings);
|
|
@@ -24,8 +24,8 @@ class NetworkDependencyTreeInsight extends Audit {
|
|
|
24
24
|
failureTitle: str_(UIStrings.title),
|
|
25
25
|
description: str_(UIStrings.description),
|
|
26
26
|
guidanceLevel: 1,
|
|
27
|
-
requiredArtifacts: ['Trace', 'SourceMaps'],
|
|
28
|
-
replacesAudits: ['critical-request-chains'],
|
|
27
|
+
requiredArtifacts: ['Trace', 'SourceMaps', 'TraceElements'],
|
|
28
|
+
replacesAudits: ['critical-request-chains', 'uses-rel-preconnect'],
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -59,15 +59,92 @@ class NetworkDependencyTreeInsight extends Audit {
|
|
|
59
59
|
*/
|
|
60
60
|
static async audit(artifacts, context) {
|
|
61
61
|
return adaptInsightToAuditProduct(artifacts, context, 'NetworkDependencyTree', (insight) => {
|
|
62
|
-
const
|
|
62
|
+
const list = [];
|
|
63
|
+
let sectionDetails;
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
sectionDetails = /** @type {LH.Audit.Details.NetworkTree} */({
|
|
65
66
|
type: 'network-tree',
|
|
66
|
-
chains,
|
|
67
|
+
chains: this.traceEngineNodesToDetailsNodes(insight.rootNodes),
|
|
67
68
|
longestChain: {
|
|
68
69
|
duration: Math.round(insight.maxTime / 1000),
|
|
69
70
|
},
|
|
70
|
-
};
|
|
71
|
+
});
|
|
72
|
+
list.push(Audit.makeListDetailSectionItem(sectionDetails));
|
|
73
|
+
|
|
74
|
+
// Preconnected origins table.
|
|
75
|
+
if (insight.preconnectedOrigins.length) {
|
|
76
|
+
/** @type {LH.Audit.Details.Table['headings']} */
|
|
77
|
+
const headings = [
|
|
78
|
+
/* eslint-disable max-len */
|
|
79
|
+
{key: 'origin', valueType: 'text', subItemsHeading: {key: 'warning'}, label: str_(UIStrings.columnOrigin)},
|
|
80
|
+
{key: 'source', valueType: 'node', label: str_(UIStrings.columnSource)},
|
|
81
|
+
/* eslint-enable max-len */
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
/** @type {LH.Audit.Details.Table['items']} */
|
|
85
|
+
const items = insight.preconnectedOrigins.map(c => {
|
|
86
|
+
const warnings = [];
|
|
87
|
+
if (c.unused) {
|
|
88
|
+
warnings.push(str_(UIStrings.unusedWarning));
|
|
89
|
+
}
|
|
90
|
+
if (c.crossorigin) {
|
|
91
|
+
warnings.push(str_(UIStrings.crossoriginWarning));
|
|
92
|
+
}
|
|
93
|
+
/** @type {LH.Audit.Details.TableSubItems} */
|
|
94
|
+
const subItems = {
|
|
95
|
+
type: 'subitems',
|
|
96
|
+
items: warnings.map(warning => ({warning})),
|
|
97
|
+
};
|
|
98
|
+
return {
|
|
99
|
+
origin: c.url,
|
|
100
|
+
source: c.source === 'DOM' ?
|
|
101
|
+
makeNodeItemForNodeId(artifacts.TraceElements, c.node_id) :
|
|
102
|
+
{type: 'text', value: c.headerText},
|
|
103
|
+
subItems,
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
sectionDetails = Audit.makeTableDetails(headings, items);
|
|
108
|
+
} else {
|
|
109
|
+
sectionDetails = /** @type {LH.Audit.Details.TextValue} */ (
|
|
110
|
+
{type: 'text', value: str_(UIStrings.noPreconnectOrigins)});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
list.push(Audit.makeListDetailSectionItem(
|
|
114
|
+
sectionDetails,
|
|
115
|
+
str_(UIStrings.preconnectOriginsTableTitle),
|
|
116
|
+
str_(UIStrings.preconnectOriginsTableDescription)));
|
|
117
|
+
|
|
118
|
+
// Estimated savings table.
|
|
119
|
+
if (insight.preconnectCandidates.length) {
|
|
120
|
+
/** @type {LH.Audit.Details.Table['headings']} */
|
|
121
|
+
const headings = [
|
|
122
|
+
{key: 'origin', valueType: 'text', label: str_(UIStrings.columnOrigin)},
|
|
123
|
+
{key: 'wastedMs', valueType: 'ms', label: str_(UIStrings.columnWastedMs)},
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
/** @type {LH.Audit.Details.Table['items']} */
|
|
127
|
+
const items = insight.preconnectCandidates.map(c => {
|
|
128
|
+
return {origin: c.origin, wastedMs: c.wastedMs};
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
sectionDetails = Audit.makeTableDetails(headings, items);
|
|
132
|
+
} else {
|
|
133
|
+
sectionDetails = /** @type {LH.Audit.Details.TextValue} */ (
|
|
134
|
+
{type: 'text', value: str_(UIStrings.noPreconnectCandidates)});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
list.push(Audit.makeListDetailSectionItem(
|
|
138
|
+
sectionDetails,
|
|
139
|
+
str_(UIStrings.estSavingTableTitle),
|
|
140
|
+
str_(UIStrings.estSavingTableDescription)));
|
|
141
|
+
|
|
142
|
+
const warnings = [];
|
|
143
|
+
if (insight.preconnectedOrigins.length > TOO_MANY_PRECONNECTS_THRESHOLD) {
|
|
144
|
+
warnings.push(str_(UIStrings.tooManyPreconnectLinksWarning));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {details: Audit.makeListDetails(list), warnings};
|
|
71
148
|
});
|
|
72
149
|
}
|
|
73
150
|
}
|
|
@@ -112,8 +112,9 @@ class LayoutShifts extends Audit {
|
|
|
112
112
|
cause: str_(UIStrings.rootCauseFontChanges),
|
|
113
113
|
});
|
|
114
114
|
}
|
|
115
|
-
|
|
115
|
+
for (const iframe of rootCauses.iframes) {
|
|
116
116
|
subItems.push({
|
|
117
|
+
extra: iframe.url ? {type: 'url', value: iframe.url} : undefined,
|
|
117
118
|
cause: str_(UIStrings.rootCauseInjectedIframe),
|
|
118
119
|
});
|
|
119
120
|
}
|
package/core/config/filters.js
CHANGED
|
@@ -36,6 +36,10 @@ function isValidArtifactDependency(dependent, dependency) {
|
|
|
36
36
|
* @param {string} pluginName
|
|
37
37
|
*/
|
|
38
38
|
function assertValidPluginName(config, pluginName) {
|
|
39
|
+
const parts = pluginName.split('/');
|
|
40
|
+
if (parts.length === 2) {
|
|
41
|
+
pluginName = parts[1];
|
|
42
|
+
}
|
|
39
43
|
if (!pluginName.startsWith('lighthouse-plugin-')) {
|
|
40
44
|
throw new Error(`plugin name '${pluginName}' does not start with 'lighthouse-plugin-'`);
|
|
41
45
|
}
|
|
@@ -9,6 +9,7 @@ import {isEqual} from 'lodash-es';
|
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
11
|
getBrowserVersion, getBenchmarkIndex, getEnvironmentWarnings,
|
|
12
|
+
getDevicePixelRatio,
|
|
12
13
|
} from './driver/environment.js';
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -20,6 +21,7 @@ import {
|
|
|
20
21
|
async function getBaseArtifacts(resolvedConfig, driver, context) {
|
|
21
22
|
const BenchmarkIndex = await getBenchmarkIndex(driver.executionContext);
|
|
22
23
|
const {userAgent, product} = await getBrowserVersion(driver.defaultSession);
|
|
24
|
+
const HostDPR = await getDevicePixelRatio(driver.executionContext);
|
|
23
25
|
|
|
24
26
|
return {
|
|
25
27
|
// Meta artifacts.
|
|
@@ -29,6 +31,7 @@ async function getBaseArtifacts(resolvedConfig, driver, context) {
|
|
|
29
31
|
settings: resolvedConfig.settings,
|
|
30
32
|
// Environment artifacts that can always be computed.
|
|
31
33
|
BenchmarkIndex,
|
|
34
|
+
HostDPR,
|
|
32
35
|
HostUserAgent: userAgent,
|
|
33
36
|
HostFormFactor: userAgent.includes('Android') || userAgent.includes('Mobile') ?
|
|
34
37
|
'mobile' : 'desktop',
|
|
@@ -14,6 +14,12 @@ export function getBrowserVersion(session: LH.Gatherer.ProtocolSession): Promise
|
|
|
14
14
|
* @return {Promise<number>}
|
|
15
15
|
*/
|
|
16
16
|
export function getBenchmarkIndex(executionContext: LH.Gatherer.Driver["executionContext"]): Promise<number>;
|
|
17
|
+
/**
|
|
18
|
+
* Computes the observed DPR.
|
|
19
|
+
* @param {LH.Gatherer.Driver['executionContext']} executionContext
|
|
20
|
+
* @return {Promise<number>}
|
|
21
|
+
*/
|
|
22
|
+
export function getDevicePixelRatio(executionContext: LH.Gatherer.Driver["executionContext"]): Promise<number>;
|
|
17
23
|
/**
|
|
18
24
|
* Returns a warning if the host device appeared to be underpowered according to BenchmarkIndex.
|
|
19
25
|
*
|
|
@@ -58,6 +58,22 @@ async function getBenchmarkIndex(executionContext) {
|
|
|
58
58
|
return indexVal;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Computes the observed DPR.
|
|
63
|
+
* @param {LH.Gatherer.Driver['executionContext']} executionContext
|
|
64
|
+
* @return {Promise<number>}
|
|
65
|
+
*/
|
|
66
|
+
async function getDevicePixelRatio(executionContext) {
|
|
67
|
+
const status = {msg: 'Host device pixel ratio', id: 'lh:gather:getDevicePixelRatio'};
|
|
68
|
+
log.time(status);
|
|
69
|
+
// eslint-disable-next-line no-undef
|
|
70
|
+
const indexVal = await executionContext.evaluate(() => devicePixelRatio, {
|
|
71
|
+
args: [],
|
|
72
|
+
});
|
|
73
|
+
log.timeEnd(status);
|
|
74
|
+
return indexVal;
|
|
75
|
+
}
|
|
76
|
+
|
|
61
77
|
/**
|
|
62
78
|
* Returns a warning if the host device appeared to be underpowered according to BenchmarkIndex.
|
|
63
79
|
*
|
|
@@ -100,6 +116,7 @@ export {
|
|
|
100
116
|
UIStrings,
|
|
101
117
|
getBrowserVersion,
|
|
102
118
|
getBenchmarkIndex,
|
|
119
|
+
getDevicePixelRatio,
|
|
103
120
|
getSlowHostCpuWarning,
|
|
104
121
|
getEnvironmentWarnings,
|
|
105
122
|
};
|
|
@@ -81,7 +81,7 @@ class InspectorIssues extends BaseGatherer {
|
|
|
81
81
|
propertyRuleIssue: [],
|
|
82
82
|
quirksModeIssue: [],
|
|
83
83
|
cookieIssue: [],
|
|
84
|
-
|
|
84
|
+
elementAccessibilityIssue: [],
|
|
85
85
|
sharedArrayBufferIssue: [],
|
|
86
86
|
sharedDictionaryIssue: [],
|
|
87
87
|
stylesheetLoadingIssue: [],
|
|
@@ -704,7 +704,10 @@ const NotRestoredReasonDescription = {
|
|
|
704
704
|
WebViewSafeBrowsingAllowlistChanged: {name: ('WebViewSafeBrowsingAllowlistChanged')},
|
|
705
705
|
WebViewDocumentStartJavascriptChanged: {name: ('WebViewDocumentStartJavascriptChanged')},
|
|
706
706
|
CacheControlNoStoreDeviceBoundSessionTerminated: {name: str_(UIStrings.cacheControlNoStore)},
|
|
707
|
-
|
|
707
|
+
CacheLimitPrunedOnModerateMemoryPressure:
|
|
708
|
+
{name: ('CacheLimitPrunedOnModerateMemoryPressure')},
|
|
709
|
+
CacheLimitPrunedOnCriticalMemoryPressure:
|
|
710
|
+
{name: ('CacheLimitPrunedOnCriticalMemoryPressure')},
|
|
708
711
|
};
|
|
709
712
|
|
|
710
713
|
export {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export namespace UIStrings {
|
|
2
2
|
let AuthorizationCoveredByWildcard: string;
|
|
3
3
|
let CanRequestURLHTTPContainingNewline: string;
|
|
4
|
+
let CharsetAutoDetectionISO2022JP: string;
|
|
4
5
|
let ChromeLoadTimesConnectionInfo: string;
|
|
5
6
|
let ChromeLoadTimesFirstPaintAfterLoadTime: string;
|
|
6
7
|
let ChromeLoadTimesWasAlternateProtocolAvailable: string;
|
|
@@ -11,7 +12,6 @@ export namespace UIStrings {
|
|
|
11
12
|
let CSSSelectorInternalMediaControlsOverlayCastButton: string;
|
|
12
13
|
let CSSValueAppearanceSliderVertical: string;
|
|
13
14
|
let DataUrlInSvgUse: string;
|
|
14
|
-
let DOMMutationEvents: string;
|
|
15
15
|
let GeolocationInsecureOrigin: string;
|
|
16
16
|
let GeolocationInsecureOriginDeprecatedNotRemoved: string;
|
|
17
17
|
let GetUserMediaInsecureOrigin: string;
|
|
@@ -54,6 +54,7 @@ export namespace UIStrings {
|
|
|
54
54
|
let TextToSpeech_DisallowedByAutoplay: string;
|
|
55
55
|
let UnloadHandler: string;
|
|
56
56
|
let V8SharedArrayBufferConstructedInExtensionWithoutIsolation: string;
|
|
57
|
+
let WebGPUAdapterIsFallbackAdapter: string;
|
|
57
58
|
let XHRJSONEncodingDetection: string;
|
|
58
59
|
let XMLHttpRequestSynchronousInNonWorkerOutsideBeforeUnload: string;
|
|
59
60
|
}
|
|
@@ -76,20 +77,25 @@ export namespace DEPRECATIONS_METADATA {
|
|
|
76
77
|
export { chromeStatusFeature_2 as chromeStatusFeature };
|
|
77
78
|
}
|
|
78
79
|
export { CanRequestURLHTTPContainingNewline_1 as CanRequestURLHTTPContainingNewline };
|
|
79
|
-
export namespace
|
|
80
|
+
export namespace CharsetAutoDetectionISO2022JP_1 {
|
|
80
81
|
let chromeStatusFeature_3: number;
|
|
81
82
|
export { chromeStatusFeature_3 as chromeStatusFeature };
|
|
82
83
|
}
|
|
83
|
-
export {
|
|
84
|
-
export namespace
|
|
84
|
+
export { CharsetAutoDetectionISO2022JP_1 as CharsetAutoDetectionISO2022JP };
|
|
85
|
+
export namespace ChromeLoadTimesConnectionInfo_1 {
|
|
85
86
|
let chromeStatusFeature_4: number;
|
|
86
87
|
export { chromeStatusFeature_4 as chromeStatusFeature };
|
|
87
88
|
}
|
|
88
|
-
export {
|
|
89
|
-
export namespace
|
|
89
|
+
export { ChromeLoadTimesConnectionInfo_1 as ChromeLoadTimesConnectionInfo };
|
|
90
|
+
export namespace ChromeLoadTimesFirstPaintAfterLoadTime_1 {
|
|
90
91
|
let chromeStatusFeature_5: number;
|
|
91
92
|
export { chromeStatusFeature_5 as chromeStatusFeature };
|
|
92
93
|
}
|
|
94
|
+
export { ChromeLoadTimesFirstPaintAfterLoadTime_1 as ChromeLoadTimesFirstPaintAfterLoadTime };
|
|
95
|
+
export namespace ChromeLoadTimesWasAlternateProtocolAvailable_1 {
|
|
96
|
+
let chromeStatusFeature_6: number;
|
|
97
|
+
export { chromeStatusFeature_6 as chromeStatusFeature };
|
|
98
|
+
}
|
|
93
99
|
export { ChromeLoadTimesWasAlternateProtocolAvailable_1 as ChromeLoadTimesWasAlternateProtocolAvailable };
|
|
94
100
|
export namespace CookieWithTruncatingChar_1 {
|
|
95
101
|
let milestone_1: number;
|
|
@@ -101,25 +107,18 @@ export namespace DEPRECATIONS_METADATA {
|
|
|
101
107
|
export { milestone_2 as milestone };
|
|
102
108
|
}
|
|
103
109
|
export { CrossOriginAccessBasedOnDocumentDomain_1 as CrossOriginAccessBasedOnDocumentDomain };
|
|
104
|
-
export namespace DOMMutationEvents_1 {
|
|
105
|
-
let chromeStatusFeature_6: number;
|
|
106
|
-
export { chromeStatusFeature_6 as chromeStatusFeature };
|
|
107
|
-
let milestone_3: number;
|
|
108
|
-
export { milestone_3 as milestone };
|
|
109
|
-
}
|
|
110
|
-
export { DOMMutationEvents_1 as DOMMutationEvents };
|
|
111
110
|
export namespace DataUrlInSvgUse_1 {
|
|
112
111
|
let chromeStatusFeature_7: number;
|
|
113
112
|
export { chromeStatusFeature_7 as chromeStatusFeature };
|
|
114
|
-
let
|
|
115
|
-
export {
|
|
113
|
+
let milestone_3: number;
|
|
114
|
+
export { milestone_3 as milestone };
|
|
116
115
|
}
|
|
117
116
|
export { DataUrlInSvgUse_1 as DataUrlInSvgUse };
|
|
118
117
|
export namespace H1UserAgentFontSizeInSection_1 {
|
|
119
118
|
let chromeStatusFeature_8: number;
|
|
120
119
|
export { chromeStatusFeature_8 as chromeStatusFeature };
|
|
121
|
-
let
|
|
122
|
-
export {
|
|
120
|
+
let milestone_4: number;
|
|
121
|
+
export { milestone_4 as milestone };
|
|
123
122
|
}
|
|
124
123
|
export { H1UserAgentFontSizeInSection_1 as H1UserAgentFontSizeInSection };
|
|
125
124
|
export namespace IdentityDigitalCredentials_1 {
|
|
@@ -135,13 +134,13 @@ export namespace DEPRECATIONS_METADATA {
|
|
|
135
134
|
export namespace InsecurePrivateNetworkSubresourceRequest_1 {
|
|
136
135
|
let chromeStatusFeature_11: number;
|
|
137
136
|
export { chromeStatusFeature_11 as chromeStatusFeature };
|
|
138
|
-
let
|
|
139
|
-
export {
|
|
137
|
+
let milestone_5: number;
|
|
138
|
+
export { milestone_5 as milestone };
|
|
140
139
|
}
|
|
141
140
|
export { InsecurePrivateNetworkSubresourceRequest_1 as InsecurePrivateNetworkSubresourceRequest };
|
|
142
141
|
export namespace LocalCSSFileExtensionRejected_1 {
|
|
143
|
-
let
|
|
144
|
-
export {
|
|
142
|
+
let milestone_6: number;
|
|
143
|
+
export { milestone_6 as milestone };
|
|
145
144
|
}
|
|
146
145
|
export { LocalCSSFileExtensionRejected_1 as LocalCSSFileExtensionRejected };
|
|
147
146
|
export namespace MediaSourceAbortRemove_1 {
|
|
@@ -157,8 +156,8 @@ export namespace DEPRECATIONS_METADATA {
|
|
|
157
156
|
export namespace NoSysexWebMIDIWithoutPermission_1 {
|
|
158
157
|
let chromeStatusFeature_14: number;
|
|
159
158
|
export { chromeStatusFeature_14 as chromeStatusFeature };
|
|
160
|
-
let
|
|
161
|
-
export {
|
|
159
|
+
let milestone_7: number;
|
|
160
|
+
export { milestone_7 as milestone };
|
|
162
161
|
}
|
|
163
162
|
export { NoSysexWebMIDIWithoutPermission_1 as NoSysexWebMIDIWithoutPermission };
|
|
164
163
|
export namespace NotificationPermissionRequestedIframe_1 {
|
|
@@ -167,20 +166,20 @@ export namespace DEPRECATIONS_METADATA {
|
|
|
167
166
|
}
|
|
168
167
|
export { NotificationPermissionRequestedIframe_1 as NotificationPermissionRequestedIframe };
|
|
169
168
|
export namespace ObsoleteCreateImageBitmapImageOrientationNone_1 {
|
|
170
|
-
let
|
|
171
|
-
export {
|
|
169
|
+
let milestone_8: number;
|
|
170
|
+
export { milestone_8 as milestone };
|
|
172
171
|
}
|
|
173
172
|
export { ObsoleteCreateImageBitmapImageOrientationNone_1 as ObsoleteCreateImageBitmapImageOrientationNone };
|
|
174
173
|
export namespace ObsoleteWebRtcCipherSuite_1 {
|
|
175
|
-
let
|
|
176
|
-
export {
|
|
174
|
+
let milestone_9: number;
|
|
175
|
+
export { milestone_9 as milestone };
|
|
177
176
|
}
|
|
178
177
|
export { ObsoleteWebRtcCipherSuite_1 as ObsoleteWebRtcCipherSuite };
|
|
179
178
|
export namespace OverflowVisibleOnReplacedElement_1 {
|
|
180
179
|
let chromeStatusFeature_16: number;
|
|
181
180
|
export { chromeStatusFeature_16 as chromeStatusFeature };
|
|
182
|
-
let
|
|
183
|
-
export {
|
|
181
|
+
let milestone_10: number;
|
|
182
|
+
export { milestone_10 as milestone };
|
|
184
183
|
}
|
|
185
184
|
export { OverflowVisibleOnReplacedElement_1 as OverflowVisibleOnReplacedElement };
|
|
186
185
|
export namespace PaymentInstruments_1 {
|
|
@@ -196,25 +195,25 @@ export namespace DEPRECATIONS_METADATA {
|
|
|
196
195
|
export namespace PersistentQuotaType_1 {
|
|
197
196
|
let chromeStatusFeature_19: number;
|
|
198
197
|
export { chromeStatusFeature_19 as chromeStatusFeature };
|
|
199
|
-
let
|
|
200
|
-
export {
|
|
198
|
+
let milestone_11: number;
|
|
199
|
+
export { milestone_11 as milestone };
|
|
201
200
|
}
|
|
202
201
|
export { PersistentQuotaType_1 as PersistentQuotaType };
|
|
203
202
|
export namespace RTCConstraintEnableDtlsSrtpFalse_1 {
|
|
204
|
-
let
|
|
205
|
-
export {
|
|
203
|
+
let milestone_12: number;
|
|
204
|
+
export { milestone_12 as milestone };
|
|
206
205
|
}
|
|
207
206
|
export { RTCConstraintEnableDtlsSrtpFalse_1 as RTCConstraintEnableDtlsSrtpFalse };
|
|
208
207
|
export namespace RTCConstraintEnableDtlsSrtpTrue_1 {
|
|
209
|
-
let
|
|
210
|
-
export {
|
|
208
|
+
let milestone_13: number;
|
|
209
|
+
export { milestone_13 as milestone };
|
|
211
210
|
}
|
|
212
211
|
export { RTCConstraintEnableDtlsSrtpTrue_1 as RTCConstraintEnableDtlsSrtpTrue };
|
|
213
212
|
export namespace RTCPeerConnectionGetStatsLegacyNonCompliant_1 {
|
|
214
213
|
let chromeStatusFeature_20: number;
|
|
215
214
|
export { chromeStatusFeature_20 as chromeStatusFeature };
|
|
216
|
-
let
|
|
217
|
-
export {
|
|
215
|
+
let milestone_14: number;
|
|
216
|
+
export { milestone_14 as milestone };
|
|
218
217
|
}
|
|
219
218
|
export { RTCPeerConnectionGetStatsLegacyNonCompliant_1 as RTCPeerConnectionGetStatsLegacyNonCompliant };
|
|
220
219
|
export namespace RequestedSubresourceWithEmbeddedCredentials_1 {
|
|
@@ -225,20 +224,20 @@ export namespace DEPRECATIONS_METADATA {
|
|
|
225
224
|
export namespace RtcpMuxPolicyNegotiate_1 {
|
|
226
225
|
let chromeStatusFeature_22: number;
|
|
227
226
|
export { chromeStatusFeature_22 as chromeStatusFeature };
|
|
228
|
-
let
|
|
229
|
-
export {
|
|
227
|
+
let milestone_15: number;
|
|
228
|
+
export { milestone_15 as milestone };
|
|
230
229
|
}
|
|
231
230
|
export { RtcpMuxPolicyNegotiate_1 as RtcpMuxPolicyNegotiate };
|
|
232
231
|
export namespace SharedArrayBufferConstructedWithoutIsolation_1 {
|
|
233
|
-
let
|
|
234
|
-
export {
|
|
232
|
+
let milestone_16: number;
|
|
233
|
+
export { milestone_16 as milestone };
|
|
235
234
|
}
|
|
236
235
|
export { SharedArrayBufferConstructedWithoutIsolation_1 as SharedArrayBufferConstructedWithoutIsolation };
|
|
237
236
|
export namespace TextToSpeech_DisallowedByAutoplay_1 {
|
|
238
237
|
let chromeStatusFeature_23: number;
|
|
239
238
|
export { chromeStatusFeature_23 as chromeStatusFeature };
|
|
240
|
-
let
|
|
241
|
-
export {
|
|
239
|
+
let milestone_17: number;
|
|
240
|
+
export { milestone_17 as milestone };
|
|
242
241
|
}
|
|
243
242
|
export { TextToSpeech_DisallowedByAutoplay_1 as TextToSpeech_DisallowedByAutoplay };
|
|
244
243
|
export namespace UnloadHandler_1 {
|
|
@@ -247,13 +246,18 @@ export namespace DEPRECATIONS_METADATA {
|
|
|
247
246
|
}
|
|
248
247
|
export { UnloadHandler_1 as UnloadHandler };
|
|
249
248
|
export namespace V8SharedArrayBufferConstructedInExtensionWithoutIsolation_1 {
|
|
250
|
-
let
|
|
251
|
-
export {
|
|
249
|
+
let milestone_18: number;
|
|
250
|
+
export { milestone_18 as milestone };
|
|
252
251
|
}
|
|
253
252
|
export { V8SharedArrayBufferConstructedInExtensionWithoutIsolation_1 as V8SharedArrayBufferConstructedInExtensionWithoutIsolation };
|
|
253
|
+
export namespace WebGPUAdapterIsFallbackAdapter_1 {
|
|
254
|
+
let chromeStatusFeature_25: number;
|
|
255
|
+
export { chromeStatusFeature_25 as chromeStatusFeature };
|
|
256
|
+
}
|
|
257
|
+
export { WebGPUAdapterIsFallbackAdapter_1 as WebGPUAdapterIsFallbackAdapter };
|
|
254
258
|
export namespace XHRJSONEncodingDetection_1 {
|
|
255
|
-
let
|
|
256
|
-
export {
|
|
259
|
+
let milestone_19: number;
|
|
260
|
+
export { milestone_19 as milestone };
|
|
257
261
|
}
|
|
258
262
|
export { XHRJSONEncodingDetection_1 as XHRJSONEncodingDetection };
|
|
259
263
|
}
|