lighthouse 9.5.0-dev.20230102 → 9.5.0-dev.20230104
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/config/config-helpers.js +1 -1
- package/core/config/config.js +19 -19
- package/core/config/filters.js +43 -41
- package/core/config/validation.js +11 -11
- package/core/gather/base-artifacts.js +3 -3
- package/core/gather/driver/prepare.js +9 -5
- package/core/gather/driver/storage.js +32 -8
- package/core/gather/navigation-runner.js +36 -27
- package/core/gather/snapshot-runner.js +7 -6
- package/core/gather/timespan-runner.js +7 -7
- package/core/index.js +3 -3
- package/core/legacy/config/config.js +30 -28
- package/core/runner.js +19 -19
- package/core/user-flow.js +2 -2
- package/dist/report/bundle.esm.js +2 -1
- package/package.json +4 -4
- package/report/renderer/topbar-features.js +2 -1
- package/shared/localization/locales/en-US.json +6 -0
- package/shared/localization/locales/en-XL.json +6 -0
- package/types/config.d.ts +4 -4
- package/types/gatherer.d.ts +1 -1
|
@@ -120,7 +120,7 @@ const mergeConfigFragment = _mergeConfigFragment;
|
|
|
120
120
|
* Merge an array of items by a caller-defined key. `mergeConfigFragment` is used to merge any items
|
|
121
121
|
* with a matching key.
|
|
122
122
|
*
|
|
123
|
-
* @template T
|
|
123
|
+
* @template {Record<string, any>} T
|
|
124
124
|
* @param {Array<T>|null|undefined} baseArray
|
|
125
125
|
* @param {Array<T>|null|undefined} extensionArray
|
|
126
126
|
* @param {(item: T) => string} keyFn
|
package/core/config/config.js
CHANGED
|
@@ -238,7 +238,7 @@ function resolveFakeNavigations(artifactDefns, settings) {
|
|
|
238
238
|
* @param {LH.Gatherer.GatherMode} gatherMode
|
|
239
239
|
* @param {LH.Config.Json=} configJSON
|
|
240
240
|
* @param {LH.Flags=} flags
|
|
241
|
-
* @return {Promise<{
|
|
241
|
+
* @return {Promise<{resolvedConfig: LH.Config.ResolvedConfig, warnings: string[]}>}
|
|
242
242
|
*/
|
|
243
243
|
async function initializeConfig(gatherMode, configJSON, flags = {}) {
|
|
244
244
|
const status = {msg: 'Initialize config', id: 'lh:config'};
|
|
@@ -256,8 +256,8 @@ async function initializeConfig(gatherMode, configJSON, flags = {}) {
|
|
|
256
256
|
|
|
257
257
|
const navigations = resolveFakeNavigations(artifacts, settings);
|
|
258
258
|
|
|
259
|
-
/** @type {LH.Config.
|
|
260
|
-
let
|
|
259
|
+
/** @type {LH.Config.ResolvedConfig} */
|
|
260
|
+
let resolvedConfig = {
|
|
261
261
|
artifacts,
|
|
262
262
|
navigations,
|
|
263
263
|
audits: await resolveAuditsToDefns(configWorkingCopy.audits, configDir),
|
|
@@ -266,25 +266,25 @@ async function initializeConfig(gatherMode, configJSON, flags = {}) {
|
|
|
266
266
|
settings,
|
|
267
267
|
};
|
|
268
268
|
|
|
269
|
-
const {warnings} = assertValidConfig(
|
|
269
|
+
const {warnings} = assertValidConfig(resolvedConfig);
|
|
270
270
|
|
|
271
|
-
|
|
272
|
-
|
|
271
|
+
resolvedConfig = filterConfigByGatherMode(resolvedConfig, gatherMode);
|
|
272
|
+
resolvedConfig = filterConfigByExplicitFilters(resolvedConfig, settings);
|
|
273
273
|
|
|
274
274
|
log.timeEnd(status);
|
|
275
|
-
return {
|
|
275
|
+
return {resolvedConfig, warnings};
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
/**
|
|
279
|
-
* @param {LH.Config.
|
|
279
|
+
* @param {LH.Config.ResolvedConfig} resolvedConfig
|
|
280
280
|
* @return {string}
|
|
281
281
|
*/
|
|
282
|
-
function getConfigDisplayString(
|
|
283
|
-
/** @type {LH.Config.
|
|
284
|
-
const
|
|
282
|
+
function getConfigDisplayString(resolvedConfig) {
|
|
283
|
+
/** @type {LH.Config.ResolvedConfig} */
|
|
284
|
+
const resolvedConfigCopy = JSON.parse(JSON.stringify(resolvedConfig));
|
|
285
285
|
|
|
286
|
-
if (
|
|
287
|
-
for (const navigation of
|
|
286
|
+
if (resolvedConfigCopy.navigations) {
|
|
287
|
+
for (const navigation of resolvedConfigCopy.navigations) {
|
|
288
288
|
for (let i = 0; i < navigation.artifacts.length; ++i) {
|
|
289
289
|
// @ts-expect-error Breaking the Config.AnyArtifactDefn type.
|
|
290
290
|
navigation.artifacts[i] = navigation.artifacts[i].id;
|
|
@@ -292,8 +292,8 @@ function getConfigDisplayString(config) {
|
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
if (
|
|
296
|
-
for (const artifactDefn of
|
|
295
|
+
if (resolvedConfigCopy.artifacts) {
|
|
296
|
+
for (const artifactDefn of resolvedConfigCopy.artifacts) {
|
|
297
297
|
// @ts-expect-error Breaking the Config.AnyArtifactDefn type.
|
|
298
298
|
artifactDefn.gatherer = artifactDefn.gatherer.path;
|
|
299
299
|
// Dependencies are not declared on Config JSON
|
|
@@ -301,8 +301,8 @@ function getConfigDisplayString(config) {
|
|
|
301
301
|
}
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
-
if (
|
|
305
|
-
for (const auditDefn of
|
|
304
|
+
if (resolvedConfigCopy.audits) {
|
|
305
|
+
for (const auditDefn of resolvedConfigCopy.audits) {
|
|
306
306
|
// @ts-expect-error Breaking the Config.AuditDefn type.
|
|
307
307
|
auditDefn.implementation = undefined;
|
|
308
308
|
if (Object.keys(auditDefn.options).length === 0) {
|
|
@@ -313,9 +313,9 @@ function getConfigDisplayString(config) {
|
|
|
313
313
|
}
|
|
314
314
|
|
|
315
315
|
// Printed config is more useful with localized strings.
|
|
316
|
-
format.replaceIcuMessages(
|
|
316
|
+
format.replaceIcuMessages(resolvedConfigCopy, resolvedConfigCopy.settings.locale);
|
|
317
317
|
|
|
318
|
-
return JSON.stringify(
|
|
318
|
+
return JSON.stringify(resolvedConfigCopy, null, 2);
|
|
319
319
|
}
|
|
320
320
|
|
|
321
321
|
export {
|
package/core/config/filters.js
CHANGED
|
@@ -39,7 +39,7 @@ const filterResistantArtifactIds = ['Stacks', 'NetworkUserAgent'];
|
|
|
39
39
|
* If `onlyCategories` is not set, this function returns the list of all audit IDs across all
|
|
40
40
|
* categories.
|
|
41
41
|
*
|
|
42
|
-
* @param {LH.Config.
|
|
42
|
+
* @param {LH.Config.ResolvedConfig['categories']} allCategories
|
|
43
43
|
* @param {string[] | undefined} onlyCategories
|
|
44
44
|
* @return {Set<string>}
|
|
45
45
|
*/
|
|
@@ -55,9 +55,9 @@ function getAuditIdsInCategories(allCategories, onlyCategories) {
|
|
|
55
55
|
/**
|
|
56
56
|
* Filters an array of artifacts down to the set that's required by the specified audits.
|
|
57
57
|
*
|
|
58
|
-
* @param {LH.Config.
|
|
59
|
-
* @param {LH.Config.
|
|
60
|
-
* @return {LH.Config.
|
|
58
|
+
* @param {LH.Config.ResolvedConfig['artifacts']} artifacts
|
|
59
|
+
* @param {LH.Config.ResolvedConfig['audits']} audits
|
|
60
|
+
* @return {LH.Config.ResolvedConfig['artifacts']}
|
|
61
61
|
*/
|
|
62
62
|
function filterArtifactsByAvailableAudits(artifacts, audits) {
|
|
63
63
|
if (!artifacts) return null;
|
|
@@ -95,9 +95,9 @@ function filterArtifactsByAvailableAudits(artifacts, audits) {
|
|
|
95
95
|
/**
|
|
96
96
|
* Filters an array of artifacts down to the set that supports the specified gather mode.
|
|
97
97
|
*
|
|
98
|
-
* @param {LH.Config.
|
|
98
|
+
* @param {LH.Config.ResolvedConfig['artifacts']} artifacts
|
|
99
99
|
* @param {LH.Gatherer.GatherMode} mode
|
|
100
|
-
* @return {LH.Config.
|
|
100
|
+
* @return {LH.Config.ResolvedConfig['artifacts']}
|
|
101
101
|
*/
|
|
102
102
|
function filterArtifactsByGatherMode(artifacts, mode) {
|
|
103
103
|
if (!artifacts) return null;
|
|
@@ -109,9 +109,9 @@ function filterArtifactsByGatherMode(artifacts, mode) {
|
|
|
109
109
|
/**
|
|
110
110
|
* Filters an array of navigations down to the set supported by the available artifacts.
|
|
111
111
|
*
|
|
112
|
-
* @param {LH.Config.
|
|
112
|
+
* @param {LH.Config.ResolvedConfig['navigations']} navigations
|
|
113
113
|
* @param {Array<LH.Config.AnyArtifactDefn>} availableArtifacts
|
|
114
|
-
* @return {LH.Config.
|
|
114
|
+
* @return {LH.Config.ResolvedConfig['navigations']}
|
|
115
115
|
*/
|
|
116
116
|
function filterNavigationsByAvailableArtifacts(navigations, availableArtifacts) {
|
|
117
117
|
if (!navigations) return navigations;
|
|
@@ -133,9 +133,9 @@ function filterNavigationsByAvailableArtifacts(navigations, availableArtifacts)
|
|
|
133
133
|
/**
|
|
134
134
|
* Filters an array of audits down to the set that can be computed using only the specified artifacts.
|
|
135
135
|
*
|
|
136
|
-
* @param {LH.Config.
|
|
136
|
+
* @param {LH.Config.ResolvedConfig['audits']} audits
|
|
137
137
|
* @param {Array<LH.Config.AnyArtifactDefn>} availableArtifacts
|
|
138
|
-
* @return {LH.Config.
|
|
138
|
+
* @return {LH.Config.ResolvedConfig['audits']}
|
|
139
139
|
*/
|
|
140
140
|
function filterAuditsByAvailableArtifacts(audits, availableArtifacts) {
|
|
141
141
|
if (!audits) return null;
|
|
@@ -152,9 +152,9 @@ function filterAuditsByAvailableArtifacts(audits, availableArtifacts) {
|
|
|
152
152
|
/**
|
|
153
153
|
* Optional `supportedModes` property can explicitly exclude an audit even if all required artifacts are available.
|
|
154
154
|
*
|
|
155
|
-
* @param {LH.Config.
|
|
155
|
+
* @param {LH.Config.ResolvedConfig['audits']} audits
|
|
156
156
|
* @param {LH.Gatherer.GatherMode} mode
|
|
157
|
-
* @return {LH.Config.
|
|
157
|
+
* @return {LH.Config.ResolvedConfig['audits']}
|
|
158
158
|
*/
|
|
159
159
|
function filterAuditsByGatherMode(audits, mode) {
|
|
160
160
|
if (!audits) return null;
|
|
@@ -168,9 +168,9 @@ function filterAuditsByGatherMode(audits, mode) {
|
|
|
168
168
|
/**
|
|
169
169
|
* Optional `supportedModes` property can explicitly exclude a category even if some audits are available.
|
|
170
170
|
*
|
|
171
|
-
* @param {LH.Config.
|
|
171
|
+
* @param {LH.Config.LegacyResolvedConfig['categories']} categories
|
|
172
172
|
* @param {LH.Gatherer.GatherMode} mode
|
|
173
|
-
* @return {LH.Config.
|
|
173
|
+
* @return {LH.Config.LegacyResolvedConfig['categories']}
|
|
174
174
|
*/
|
|
175
175
|
function filterCategoriesByGatherMode(categories, mode) {
|
|
176
176
|
if (!categories) return null;
|
|
@@ -185,9 +185,9 @@ function filterCategoriesByGatherMode(categories, mode) {
|
|
|
185
185
|
/**
|
|
186
186
|
* Filters a categories object and their auditRefs down to the specified category ids.
|
|
187
187
|
*
|
|
188
|
-
* @param {LH.Config.
|
|
188
|
+
* @param {LH.Config.LegacyResolvedConfig['categories']} categories
|
|
189
189
|
* @param {string[] | null | undefined} onlyCategories
|
|
190
|
-
* @return {LH.Config.
|
|
190
|
+
* @return {LH.Config.LegacyResolvedConfig['categories']}
|
|
191
191
|
*/
|
|
192
192
|
function filterCategoriesByExplicitFilters(categories, onlyCategories) {
|
|
193
193
|
if (!categories || !onlyCategories) return categories;
|
|
@@ -201,7 +201,7 @@ function filterCategoriesByExplicitFilters(categories, onlyCategories) {
|
|
|
201
201
|
* Logs a warning if any specified onlyCategory is not a known category that can
|
|
202
202
|
* be included.
|
|
203
203
|
*
|
|
204
|
-
* @param {LH.Config.
|
|
204
|
+
* @param {LH.Config.LegacyResolvedConfig['categories']} allCategories
|
|
205
205
|
* @param {string[] | null} onlyCategories
|
|
206
206
|
* @return {void}
|
|
207
207
|
*/
|
|
@@ -219,9 +219,9 @@ function warnOnUnknownOnlyCategories(allCategories, onlyCategories) {
|
|
|
219
219
|
* Filters a categories object and their auditRefs down to the set that can be computed using
|
|
220
220
|
* only the specified audits.
|
|
221
221
|
*
|
|
222
|
-
* @param {LH.Config.
|
|
222
|
+
* @param {LH.Config.LegacyResolvedConfig['categories']} categories
|
|
223
223
|
* @param {Array<LH.Config.AuditDefn>} availableAudits
|
|
224
|
-
* @return {LH.Config.
|
|
224
|
+
* @return {LH.Config.LegacyResolvedConfig['categories']}
|
|
225
225
|
*/
|
|
226
226
|
function filterCategoriesByAvailableAudits(categories, availableAudits) {
|
|
227
227
|
if (!categories) return categories;
|
|
@@ -257,19 +257,19 @@ function filterCategoriesByAvailableAudits(categories, availableAudits) {
|
|
|
257
257
|
/**
|
|
258
258
|
* Filters a config's artifacts, audits, and categories down to the set that supports the specified gather mode.
|
|
259
259
|
*
|
|
260
|
-
* @param {LH.Config.
|
|
260
|
+
* @param {LH.Config.ResolvedConfig} resolvedConfig
|
|
261
261
|
* @param {LH.Gatherer.GatherMode} mode
|
|
262
|
-
* @return {LH.Config.
|
|
262
|
+
* @return {LH.Config.ResolvedConfig}
|
|
263
263
|
*/
|
|
264
|
-
function filterConfigByGatherMode(
|
|
265
|
-
const artifacts = filterArtifactsByGatherMode(
|
|
266
|
-
const supportedAudits = filterAuditsByGatherMode(
|
|
264
|
+
function filterConfigByGatherMode(resolvedConfig, mode) {
|
|
265
|
+
const artifacts = filterArtifactsByGatherMode(resolvedConfig.artifacts, mode);
|
|
266
|
+
const supportedAudits = filterAuditsByGatherMode(resolvedConfig.audits, mode);
|
|
267
267
|
const audits = filterAuditsByAvailableArtifacts(supportedAudits, artifacts || []);
|
|
268
|
-
const supportedCategories = filterCategoriesByGatherMode(
|
|
268
|
+
const supportedCategories = filterCategoriesByGatherMode(resolvedConfig.categories, mode);
|
|
269
269
|
const categories = filterCategoriesByAvailableAudits(supportedCategories, audits || []);
|
|
270
270
|
|
|
271
271
|
return {
|
|
272
|
-
...
|
|
272
|
+
...resolvedConfig,
|
|
273
273
|
artifacts,
|
|
274
274
|
audits,
|
|
275
275
|
categories,
|
|
@@ -280,22 +280,22 @@ function filterConfigByGatherMode(config, mode) {
|
|
|
280
280
|
* Filters a config's artifacts, audits, and categories down to the requested set.
|
|
281
281
|
* Skip audits overrides inclusion via `onlyAudits`/`onlyCategories`.
|
|
282
282
|
*
|
|
283
|
-
* @param {LH.Config.
|
|
283
|
+
* @param {LH.Config.ResolvedConfig} resolvedConfig
|
|
284
284
|
* @param {Pick<LH.Config.Settings, 'onlyAudits'|'onlyCategories'|'skipAudits'>} filters
|
|
285
|
-
* @return {LH.Config.
|
|
285
|
+
* @return {LH.Config.ResolvedConfig}
|
|
286
286
|
*/
|
|
287
|
-
function filterConfigByExplicitFilters(
|
|
287
|
+
function filterConfigByExplicitFilters(resolvedConfig, filters) {
|
|
288
288
|
const {onlyAudits, onlyCategories, skipAudits} = filters;
|
|
289
289
|
|
|
290
|
-
warnOnUnknownOnlyCategories(
|
|
290
|
+
warnOnUnknownOnlyCategories(resolvedConfig.categories, onlyCategories);
|
|
291
291
|
|
|
292
|
-
let baseAuditIds = getAuditIdsInCategories(
|
|
292
|
+
let baseAuditIds = getAuditIdsInCategories(resolvedConfig.categories, undefined);
|
|
293
293
|
if (onlyCategories) {
|
|
294
|
-
baseAuditIds = getAuditIdsInCategories(
|
|
294
|
+
baseAuditIds = getAuditIdsInCategories(resolvedConfig.categories, onlyCategories);
|
|
295
295
|
} else if (onlyAudits) {
|
|
296
296
|
baseAuditIds = new Set();
|
|
297
|
-
} else if (!
|
|
298
|
-
baseAuditIds = new Set(
|
|
297
|
+
} else if (!resolvedConfig.categories || !Object.keys(resolvedConfig.categories).length) {
|
|
298
|
+
baseAuditIds = new Set(resolvedConfig.audits?.map(audit => audit.implementation.meta.id));
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
const auditIdsToKeep = new Set(
|
|
@@ -306,17 +306,19 @@ function filterConfigByExplicitFilters(config, filters) {
|
|
|
306
306
|
].filter(auditId => !skipAudits || !skipAudits.includes(auditId))
|
|
307
307
|
);
|
|
308
308
|
|
|
309
|
-
const audits = auditIdsToKeep.size &&
|
|
310
|
-
|
|
311
|
-
|
|
309
|
+
const audits = auditIdsToKeep.size && resolvedConfig.audits ?
|
|
310
|
+
resolvedConfig.audits.filter(audit => auditIdsToKeep.has(audit.implementation.meta.id)) :
|
|
311
|
+
resolvedConfig.audits;
|
|
312
312
|
|
|
313
|
-
const availableCategories =
|
|
313
|
+
const availableCategories =
|
|
314
|
+
filterCategoriesByAvailableAudits(resolvedConfig.categories, audits || []);
|
|
314
315
|
const categories = filterCategoriesByExplicitFilters(availableCategories, onlyCategories);
|
|
315
|
-
const artifacts = filterArtifactsByAvailableAudits(
|
|
316
|
-
const navigations =
|
|
316
|
+
const artifacts = filterArtifactsByAvailableAudits(resolvedConfig.artifacts, audits);
|
|
317
|
+
const navigations =
|
|
318
|
+
filterNavigationsByAvailableArtifacts(resolvedConfig.navigations, artifacts || []);
|
|
317
319
|
|
|
318
320
|
return {
|
|
319
|
-
...
|
|
321
|
+
...resolvedConfig,
|
|
320
322
|
artifacts,
|
|
321
323
|
navigations,
|
|
322
324
|
audits,
|
|
@@ -79,7 +79,7 @@ function assertValidFRGatherer(gathererDefn) {
|
|
|
79
79
|
|
|
80
80
|
/**
|
|
81
81
|
* Throws an error if the provided object does not implement the required navigations interface.
|
|
82
|
-
* @param {LH.Config.
|
|
82
|
+
* @param {LH.Config.ResolvedConfig['navigations']} navigationsDefn
|
|
83
83
|
* @return {{warnings: string[]}}
|
|
84
84
|
*/
|
|
85
85
|
function assertValidFRNavigations(navigationsDefn) {
|
|
@@ -164,9 +164,9 @@ function assertValidAudit(auditDefinition) {
|
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
/**
|
|
167
|
-
* @param {LH.Config.
|
|
168
|
-
* @param {LH.Config.
|
|
169
|
-
* @param {LH.Config.
|
|
167
|
+
* @param {LH.Config.ResolvedConfig['categories']} categories
|
|
168
|
+
* @param {LH.Config.ResolvedConfig['audits']} audits
|
|
169
|
+
* @param {LH.Config.ResolvedConfig['groups']} groups
|
|
170
170
|
*/
|
|
171
171
|
function assertValidCategories(categories, audits, groups) {
|
|
172
172
|
if (!categories) {
|
|
@@ -247,22 +247,22 @@ function assertArtifactTopologicalOrder(navigations) {
|
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
/**
|
|
250
|
-
* @param {LH.Config.
|
|
250
|
+
* @param {LH.Config.ResolvedConfig} resolvedConfig
|
|
251
251
|
* @return {{warnings: string[]}}
|
|
252
252
|
*/
|
|
253
|
-
function assertValidConfig(
|
|
254
|
-
const {warnings} = assertValidFRNavigations(
|
|
253
|
+
function assertValidConfig(resolvedConfig) {
|
|
254
|
+
const {warnings} = assertValidFRNavigations(resolvedConfig.navigations);
|
|
255
255
|
|
|
256
|
-
for (const artifactDefn of
|
|
256
|
+
for (const artifactDefn of resolvedConfig.artifacts || []) {
|
|
257
257
|
assertValidFRGatherer(artifactDefn.gatherer);
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
-
for (const auditDefn of
|
|
260
|
+
for (const auditDefn of resolvedConfig.audits || []) {
|
|
261
261
|
assertValidAudit(auditDefn);
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
assertValidCategories(
|
|
265
|
-
assertValidSettings(
|
|
264
|
+
assertValidCategories(resolvedConfig.categories, resolvedConfig.audits, resolvedConfig.groups);
|
|
265
|
+
assertValidSettings(resolvedConfig.settings);
|
|
266
266
|
return {warnings};
|
|
267
267
|
}
|
|
268
268
|
|
|
@@ -12,12 +12,12 @@ import {
|
|
|
12
12
|
} from './driver/environment.js';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* @param {LH.Config.
|
|
15
|
+
* @param {LH.Config.ResolvedConfig} resolvedConfig
|
|
16
16
|
* @param {LH.Gatherer.FRTransitionalDriver} driver
|
|
17
17
|
* @param {{gatherMode: LH.Gatherer.GatherMode}} context
|
|
18
18
|
* @return {Promise<LH.BaseArtifacts>}
|
|
19
19
|
*/
|
|
20
|
-
async function getBaseArtifacts(
|
|
20
|
+
async function getBaseArtifacts(resolvedConfig, driver, context) {
|
|
21
21
|
const BenchmarkIndex = await getBenchmarkIndex(driver.executionContext);
|
|
22
22
|
const {userAgent} = await getBrowserVersion(driver.defaultSession);
|
|
23
23
|
|
|
@@ -26,7 +26,7 @@ async function getBaseArtifacts(config, driver, context) {
|
|
|
26
26
|
fetchTime: new Date().toJSON(),
|
|
27
27
|
Timing: [],
|
|
28
28
|
LighthouseRunWarnings: [],
|
|
29
|
-
settings:
|
|
29
|
+
settings: resolvedConfig.settings,
|
|
30
30
|
// Environment artifacts that can always be computed.
|
|
31
31
|
BenchmarkIndex,
|
|
32
32
|
HostUserAgent: userAgent,
|
|
@@ -70,6 +70,7 @@ async function dismissJavaScriptDialogs(session) {
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
|
+
* Reset the storage and warn if any stored data could be affecting the scores.
|
|
73
74
|
* @param {LH.Gatherer.FRProtocolSession} session
|
|
74
75
|
* @param {string} url
|
|
75
76
|
* @return {Promise<{warnings: Array<LH.IcuMessage>}>}
|
|
@@ -78,11 +79,14 @@ async function resetStorageForUrl(session, url) {
|
|
|
78
79
|
/** @type {Array<LH.IcuMessage>} */
|
|
79
80
|
const warnings = [];
|
|
80
81
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
await storage.clearDataForOrigin(session, url);
|
|
85
|
-
|
|
82
|
+
const importantStorageWarning = await storage.getImportantStorageWarning(session, url);
|
|
83
|
+
if (importantStorageWarning) warnings.push(importantStorageWarning);
|
|
84
|
+
|
|
85
|
+
const clearDataWarnings = await storage.clearDataForOrigin(session, url);
|
|
86
|
+
warnings.push(...clearDataWarnings);
|
|
87
|
+
|
|
88
|
+
const clearCacheWarnings = await storage.clearBrowserCaches(session);
|
|
89
|
+
warnings.push(...clearCacheWarnings);
|
|
86
90
|
|
|
87
91
|
return {warnings};
|
|
88
92
|
}
|
|
@@ -8,6 +8,7 @@ import log from 'lighthouse-logger';
|
|
|
8
8
|
|
|
9
9
|
import * as i18n from '../../lib/i18n/i18n.js';
|
|
10
10
|
|
|
11
|
+
/* eslint-disable max-len */
|
|
11
12
|
const UIStrings = {
|
|
12
13
|
/**
|
|
13
14
|
* @description A warning that previously-saved data may have affected the measured performance and instructions on how to avoid the problem. "locations" will be a list of possible types of data storage locations, e.g. "IndexedDB", "Local Storage", or "Web SQL".
|
|
@@ -22,7 +23,12 @@ const UIStrings = {
|
|
|
22
23
|
`Audit this page in an incognito window to prevent those resources ` +
|
|
23
24
|
`from affecting your scores.}
|
|
24
25
|
}`,
|
|
26
|
+
/** A warning that the data in the browser cache may have affected the measured performance because the operation to clear the browser cache timed out. */
|
|
27
|
+
warningCacheTimeout: 'Clearing the browser cache timed out. Try auditing this page again and file a bug if the issue persists.',
|
|
28
|
+
/** A warning that the data on the page's origin may have affected the measured performance because the operation to clear the origin data timed out. */
|
|
29
|
+
warningOriginDataTimeout: 'Clearing the origin data timed out. Try auditing this page again and file a bug if the issue persists.',
|
|
25
30
|
};
|
|
31
|
+
/* eslint-enable max-len */
|
|
26
32
|
|
|
27
33
|
const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
28
34
|
|
|
@@ -30,12 +36,14 @@ const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
|
|
|
30
36
|
/**
|
|
31
37
|
* @param {LH.Gatherer.FRProtocolSession} session
|
|
32
38
|
* @param {string} url
|
|
33
|
-
* @return {Promise<
|
|
39
|
+
* @return {Promise<LH.IcuMessage[]>}
|
|
34
40
|
*/
|
|
35
41
|
async function clearDataForOrigin(session, url) {
|
|
36
42
|
const status = {msg: 'Cleaning origin data', id: 'lh:storage:clearDataForOrigin'};
|
|
37
43
|
log.time(status);
|
|
38
44
|
|
|
45
|
+
const warnings = [];
|
|
46
|
+
|
|
39
47
|
const origin = new URL(url).origin;
|
|
40
48
|
|
|
41
49
|
// Clear some types of storage.
|
|
@@ -62,12 +70,15 @@ async function clearDataForOrigin(session, url) {
|
|
|
62
70
|
} catch (err) {
|
|
63
71
|
if (/** @type {LH.LighthouseError} */ (err).code === 'PROTOCOL_TIMEOUT') {
|
|
64
72
|
log.warn('Driver', 'clearDataForOrigin timed out');
|
|
73
|
+
warnings.push(str_(UIStrings.warningOriginDataTimeout));
|
|
65
74
|
} else {
|
|
66
75
|
throw err;
|
|
67
76
|
}
|
|
68
77
|
} finally {
|
|
69
78
|
log.timeEnd(status);
|
|
70
79
|
}
|
|
80
|
+
|
|
81
|
+
return warnings;
|
|
71
82
|
}
|
|
72
83
|
|
|
73
84
|
/**
|
|
@@ -102,19 +113,32 @@ async function getImportantStorageWarning(session, url) {
|
|
|
102
113
|
/**
|
|
103
114
|
* Clear the network cache on disk and in memory.
|
|
104
115
|
* @param {LH.Gatherer.FRProtocolSession} session
|
|
105
|
-
* @return {Promise<
|
|
116
|
+
* @return {Promise<LH.IcuMessage[]>}
|
|
106
117
|
*/
|
|
107
118
|
async function clearBrowserCaches(session) {
|
|
108
119
|
const status = {msg: 'Cleaning browser cache', id: 'lh:storage:clearBrowserCaches'};
|
|
109
120
|
log.time(status);
|
|
110
121
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
122
|
+
const warnings = [];
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
// Wipe entire disk cache
|
|
126
|
+
await session.sendCommand('Network.clearBrowserCache');
|
|
127
|
+
// Toggle 'Disable Cache' to evict the memory cache
|
|
128
|
+
await session.sendCommand('Network.setCacheDisabled', {cacheDisabled: true});
|
|
129
|
+
await session.sendCommand('Network.setCacheDisabled', {cacheDisabled: false});
|
|
130
|
+
} catch (err) {
|
|
131
|
+
if (/** @type {LH.LighthouseError} */ (err).code === 'PROTOCOL_TIMEOUT') {
|
|
132
|
+
log.warn('Driver', 'clearBrowserCaches timed out');
|
|
133
|
+
warnings.push(str_(UIStrings.warningCacheTimeout));
|
|
134
|
+
} else {
|
|
135
|
+
throw err;
|
|
136
|
+
}
|
|
137
|
+
} finally {
|
|
138
|
+
log.timeEnd(status);
|
|
139
|
+
}
|
|
116
140
|
|
|
117
|
-
|
|
141
|
+
return warnings;
|
|
118
142
|
}
|
|
119
143
|
|
|
120
144
|
export {
|
|
@@ -29,7 +29,7 @@ import {NetworkRecords} from '../computed/network-records.js';
|
|
|
29
29
|
* @typedef NavigationContext
|
|
30
30
|
* @property {Driver} driver
|
|
31
31
|
* @property {LH.Puppeteer.Page} page
|
|
32
|
-
* @property {LH.Config.
|
|
32
|
+
* @property {LH.Config.ResolvedConfig} resolvedConfig
|
|
33
33
|
* @property {LH.Config.NavigationDefn} navigation
|
|
34
34
|
* @property {LH.NavigationRequestor} requestor
|
|
35
35
|
* @property {LH.FRBaseArtifacts} baseArtifacts
|
|
@@ -42,20 +42,20 @@ const DEFAULT_HOSTNAME = '127.0.0.1';
|
|
|
42
42
|
const DEFAULT_PORT = 9222;
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
* @param {{driver: Driver,
|
|
45
|
+
* @param {{driver: Driver, resolvedConfig: LH.Config.ResolvedConfig, requestor: LH.NavigationRequestor}} args
|
|
46
46
|
* @return {Promise<{baseArtifacts: LH.FRBaseArtifacts}>}
|
|
47
47
|
*/
|
|
48
|
-
async function _setup({driver,
|
|
48
|
+
async function _setup({driver, resolvedConfig, requestor}) {
|
|
49
49
|
await driver.connect();
|
|
50
50
|
|
|
51
51
|
// We can't trigger the navigation through user interaction if we reset the page before starting.
|
|
52
|
-
if (typeof requestor === 'string' && !
|
|
52
|
+
if (typeof requestor === 'string' && !resolvedConfig.settings.skipAboutBlank) {
|
|
53
53
|
await gotoURL(driver, defaultNavigationConfig.blankPage, {waitUntil: ['navigated']});
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
const baseArtifacts = await getBaseArtifacts(
|
|
56
|
+
const baseArtifacts = await getBaseArtifacts(resolvedConfig, driver, {gatherMode: 'navigation'});
|
|
57
57
|
|
|
58
|
-
await prepare.prepareTargetForNavigationMode(driver,
|
|
58
|
+
await prepare.prepareTargetForNavigationMode(driver, resolvedConfig.settings);
|
|
59
59
|
|
|
60
60
|
return {baseArtifacts};
|
|
61
61
|
}
|
|
@@ -64,15 +64,15 @@ async function _setup({driver, config, requestor}) {
|
|
|
64
64
|
* @param {NavigationContext} navigationContext
|
|
65
65
|
* @return {Promise<{warnings: Array<LH.IcuMessage>}>}
|
|
66
66
|
*/
|
|
67
|
-
async function _setupNavigation({requestor, driver, navigation,
|
|
67
|
+
async function _setupNavigation({requestor, driver, navigation, resolvedConfig}) {
|
|
68
68
|
// We can't trigger the navigation through user interaction if we reset the page before starting.
|
|
69
|
-
if (typeof requestor === 'string' && !
|
|
69
|
+
if (typeof requestor === 'string' && !resolvedConfig.settings.skipAboutBlank) {
|
|
70
70
|
await gotoURL(driver, navigation.blankPage, {...navigation, waitUntil: ['navigated']});
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
const {warnings} = await prepare.prepareTargetForIndividualNavigation(
|
|
74
74
|
driver.defaultSession,
|
|
75
|
-
|
|
75
|
+
resolvedConfig.settings,
|
|
76
76
|
{
|
|
77
77
|
...navigation,
|
|
78
78
|
requestor,
|
|
@@ -94,14 +94,14 @@ async function _cleanupNavigation({driver}) {
|
|
|
94
94
|
* @return {Promise<{requestedUrl: string, mainDocumentUrl: string, navigationError: LH.LighthouseError | undefined, warnings: Array<LH.IcuMessage>}>}
|
|
95
95
|
*/
|
|
96
96
|
async function _navigate(navigationContext) {
|
|
97
|
-
const {driver,
|
|
97
|
+
const {driver, resolvedConfig, requestor} = navigationContext;
|
|
98
98
|
|
|
99
99
|
try {
|
|
100
100
|
const {requestedUrl, mainDocumentUrl, warnings} = await gotoURL(driver, requestor, {
|
|
101
101
|
...navigationContext.navigation,
|
|
102
|
-
debugNavigation:
|
|
103
|
-
maxWaitForFcp:
|
|
104
|
-
maxWaitForLoad:
|
|
102
|
+
debugNavigation: resolvedConfig.settings.debugNavigation,
|
|
103
|
+
maxWaitForFcp: resolvedConfig.settings.maxWaitForFcp,
|
|
104
|
+
maxWaitForLoad: resolvedConfig.settings.maxWaitForLoad,
|
|
105
105
|
waitUntil: navigationContext.navigation.pauseAfterFcpMs ? ['fcp', 'load'] : ['load'],
|
|
106
106
|
});
|
|
107
107
|
return {requestedUrl, mainDocumentUrl, navigationError: undefined, warnings};
|
|
@@ -181,7 +181,7 @@ async function _computeNavigationResult(
|
|
|
181
181
|
: navigationError;
|
|
182
182
|
|
|
183
183
|
if (pageLoadError) {
|
|
184
|
-
const locale = navigationContext.
|
|
184
|
+
const locale = navigationContext.resolvedConfig.settings.locale;
|
|
185
185
|
const localizedMessage = format.getFormatted(pageLoadError.friendlyMessage, locale);
|
|
186
186
|
log.error('NavigationRunner', localizedMessage, navigateResult.requestedUrl);
|
|
187
187
|
|
|
@@ -223,7 +223,7 @@ async function _navigation(navigationContext) {
|
|
|
223
223
|
artifactDefinitions: navigationContext.navigation.artifacts,
|
|
224
224
|
artifactState,
|
|
225
225
|
baseArtifacts: navigationContext.baseArtifacts,
|
|
226
|
-
settings: navigationContext.
|
|
226
|
+
settings: navigationContext.resolvedConfig.settings,
|
|
227
227
|
};
|
|
228
228
|
|
|
229
229
|
const setupResult = await _setupNavigation(navigationContext);
|
|
@@ -250,24 +250,33 @@ async function _navigation(navigationContext) {
|
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
/**
|
|
253
|
-
* @param {{driver: Driver, page: LH.Puppeteer.Page,
|
|
253
|
+
* @param {{driver: Driver, page: LH.Puppeteer.Page, resolvedConfig: LH.Config.ResolvedConfig, requestor: LH.NavigationRequestor; baseArtifacts: LH.FRBaseArtifacts, computedCache: NavigationContext['computedCache']}} args
|
|
254
254
|
* @return {Promise<{artifacts: Partial<LH.FRArtifacts & LH.FRBaseArtifacts>}>}
|
|
255
255
|
*/
|
|
256
|
-
async function _navigations(
|
|
257
|
-
|
|
256
|
+
async function _navigations(args) {
|
|
257
|
+
const {
|
|
258
|
+
driver,
|
|
259
|
+
page,
|
|
260
|
+
resolvedConfig,
|
|
261
|
+
requestor,
|
|
262
|
+
baseArtifacts,
|
|
263
|
+
computedCache,
|
|
264
|
+
} = args;
|
|
265
|
+
|
|
266
|
+
if (!resolvedConfig.navigations) throw new Error('No navigations configured');
|
|
258
267
|
|
|
259
268
|
/** @type {Partial<LH.FRArtifacts & LH.FRBaseArtifacts>} */
|
|
260
269
|
const artifacts = {};
|
|
261
270
|
/** @type {Array<LH.IcuMessage>} */
|
|
262
271
|
const LighthouseRunWarnings = [];
|
|
263
272
|
|
|
264
|
-
for (const navigation of
|
|
273
|
+
for (const navigation of resolvedConfig.navigations) {
|
|
265
274
|
const navigationContext = {
|
|
266
275
|
driver,
|
|
267
276
|
page,
|
|
268
277
|
navigation,
|
|
269
278
|
requestor,
|
|
270
|
-
|
|
279
|
+
resolvedConfig,
|
|
271
280
|
baseArtifacts,
|
|
272
281
|
computedCache,
|
|
273
282
|
};
|
|
@@ -290,10 +299,10 @@ async function _navigations({driver, page, config, requestor, baseArtifacts, com
|
|
|
290
299
|
}
|
|
291
300
|
|
|
292
301
|
/**
|
|
293
|
-
* @param {{requestedUrl?: string, driver: Driver,
|
|
302
|
+
* @param {{requestedUrl?: string, driver: Driver, resolvedConfig: LH.Config.ResolvedConfig}} args
|
|
294
303
|
*/
|
|
295
|
-
async function _cleanup({requestedUrl, driver,
|
|
296
|
-
const didResetStorage = !
|
|
304
|
+
async function _cleanup({requestedUrl, driver, resolvedConfig}) {
|
|
305
|
+
const didResetStorage = !resolvedConfig.settings.disableStorageReset && requestedUrl;
|
|
297
306
|
if (didResetStorage) await storage.clearDataForOrigin(driver.defaultSession, requestedUrl);
|
|
298
307
|
|
|
299
308
|
await driver.disconnect();
|
|
@@ -306,15 +315,15 @@ async function _cleanup({requestedUrl, driver, config}) {
|
|
|
306
315
|
* @return {Promise<LH.Gatherer.FRGatherResult>}
|
|
307
316
|
*/
|
|
308
317
|
async function navigationGather(page, requestor, options = {}) {
|
|
309
|
-
const {flags = {}} = options;
|
|
318
|
+
const {flags = {}, config} = options;
|
|
310
319
|
log.setLevel(flags.logLevel || 'error');
|
|
311
320
|
|
|
312
|
-
const {
|
|
321
|
+
const {resolvedConfig} = await initializeConfig('navigation', config, flags);
|
|
313
322
|
const computedCache = new Map();
|
|
314
323
|
|
|
315
324
|
const isCallback = typeof requestor === 'function';
|
|
316
325
|
|
|
317
|
-
const runnerOptions = {
|
|
326
|
+
const runnerOptions = {resolvedConfig, computedCache};
|
|
318
327
|
const artifacts = await Runner.gather(
|
|
319
328
|
async () => {
|
|
320
329
|
const normalizedRequestor = isCallback ? requestor : UrlUtils.normalizeUrl(requestor);
|
|
@@ -330,7 +339,7 @@ async function navigationGather(page, requestor, options = {}) {
|
|
|
330
339
|
const driver = new Driver(page);
|
|
331
340
|
const context = {
|
|
332
341
|
driver,
|
|
333
|
-
|
|
342
|
+
resolvedConfig,
|
|
334
343
|
requestor: normalizedRequestor,
|
|
335
344
|
};
|
|
336
345
|
const {baseArtifacts} = await _setup(context);
|
|
@@ -18,10 +18,10 @@ import {getBaseArtifacts, finalizeArtifacts} from './base-artifacts.js';
|
|
|
18
18
|
* @return {Promise<LH.Gatherer.FRGatherResult>}
|
|
19
19
|
*/
|
|
20
20
|
async function snapshotGather(page, options = {}) {
|
|
21
|
-
const {flags = {}} = options;
|
|
21
|
+
const {flags = {}, config} = options;
|
|
22
22
|
log.setLevel(flags.logLevel || 'error');
|
|
23
23
|
|
|
24
|
-
const {
|
|
24
|
+
const {resolvedConfig} = await initializeConfig('snapshot', config, flags);
|
|
25
25
|
const driver = new Driver(page);
|
|
26
26
|
await driver.connect();
|
|
27
27
|
|
|
@@ -29,15 +29,16 @@ async function snapshotGather(page, options = {}) {
|
|
|
29
29
|
const computedCache = new Map();
|
|
30
30
|
const url = await driver.url();
|
|
31
31
|
|
|
32
|
-
const runnerOptions = {
|
|
32
|
+
const runnerOptions = {resolvedConfig, computedCache};
|
|
33
33
|
const artifacts = await Runner.gather(
|
|
34
34
|
async () => {
|
|
35
|
-
const baseArtifacts =
|
|
35
|
+
const baseArtifacts =
|
|
36
|
+
await getBaseArtifacts(resolvedConfig, driver, {gatherMode: 'snapshot'});
|
|
36
37
|
baseArtifacts.URL = {
|
|
37
38
|
finalDisplayedUrl: url,
|
|
38
39
|
};
|
|
39
40
|
|
|
40
|
-
const artifactDefinitions =
|
|
41
|
+
const artifactDefinitions = resolvedConfig.artifacts || [];
|
|
41
42
|
const artifactState = getEmptyArtifactState();
|
|
42
43
|
await collectPhaseArtifacts({
|
|
43
44
|
phase: 'getArtifact',
|
|
@@ -48,7 +49,7 @@ async function snapshotGather(page, options = {}) {
|
|
|
48
49
|
artifactDefinitions,
|
|
49
50
|
artifactState,
|
|
50
51
|
computedCache,
|
|
51
|
-
settings:
|
|
52
|
+
settings: resolvedConfig.settings,
|
|
52
53
|
});
|
|
53
54
|
|
|
54
55
|
await driver.disconnect();
|
|
@@ -19,17 +19,17 @@ import {getBaseArtifacts, finalizeArtifacts} from './base-artifacts.js';
|
|
|
19
19
|
* @return {Promise<{endTimespanGather(): Promise<LH.Gatherer.FRGatherResult>}>}
|
|
20
20
|
*/
|
|
21
21
|
async function startTimespanGather(page, options = {}) {
|
|
22
|
-
const {flags = {}} = options;
|
|
22
|
+
const {flags = {}, config} = options;
|
|
23
23
|
log.setLevel(flags.logLevel || 'error');
|
|
24
24
|
|
|
25
|
-
const {
|
|
25
|
+
const {resolvedConfig} = await initializeConfig('timespan', config, flags);
|
|
26
26
|
const driver = new Driver(page);
|
|
27
27
|
await driver.connect();
|
|
28
28
|
|
|
29
29
|
/** @type {Map<string, LH.ArbitraryEqualityMap>} */
|
|
30
30
|
const computedCache = new Map();
|
|
31
|
-
const artifactDefinitions =
|
|
32
|
-
const baseArtifacts = await getBaseArtifacts(
|
|
31
|
+
const artifactDefinitions = resolvedConfig.artifacts || [];
|
|
32
|
+
const baseArtifacts = await getBaseArtifacts(resolvedConfig, driver, {gatherMode: 'timespan'});
|
|
33
33
|
const artifactState = getEmptyArtifactState();
|
|
34
34
|
/** @type {Omit<import('./runner-helpers.js').CollectPhaseArtifactOptions, 'phase'>} */
|
|
35
35
|
const phaseOptions = {
|
|
@@ -40,10 +40,10 @@ async function startTimespanGather(page, options = {}) {
|
|
|
40
40
|
baseArtifacts,
|
|
41
41
|
computedCache,
|
|
42
42
|
gatherMode: 'timespan',
|
|
43
|
-
settings:
|
|
43
|
+
settings: resolvedConfig.settings,
|
|
44
44
|
};
|
|
45
45
|
|
|
46
|
-
await prepareTargetForTimespanMode(driver,
|
|
46
|
+
await prepareTargetForTimespanMode(driver, resolvedConfig.settings);
|
|
47
47
|
await collectPhaseArtifacts({phase: 'startInstrumentation', ...phaseOptions});
|
|
48
48
|
await collectPhaseArtifacts({phase: 'startSensitiveInstrumentation', ...phaseOptions});
|
|
49
49
|
|
|
@@ -51,7 +51,7 @@ async function startTimespanGather(page, options = {}) {
|
|
|
51
51
|
async endTimespanGather() {
|
|
52
52
|
const finalDisplayedUrl = await driver.url();
|
|
53
53
|
|
|
54
|
-
const runnerOptions = {
|
|
54
|
+
const runnerOptions = {resolvedConfig, computedCache};
|
|
55
55
|
const artifacts = await Runner.gather(
|
|
56
56
|
async () => {
|
|
57
57
|
baseArtifacts.URL = {finalDisplayedUrl};
|
package/core/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import log from 'lighthouse-logger';
|
|
|
8
8
|
|
|
9
9
|
import {Runner} from './runner.js';
|
|
10
10
|
import {CriConnection} from './legacy/gather/connections/cri.js';
|
|
11
|
-
import {
|
|
11
|
+
import {LegacyResolvedConfig} from './legacy/config/config.js';
|
|
12
12
|
import UrlUtils from './lib/url-utils.js';
|
|
13
13
|
import {Driver} from './legacy/gather/driver.js';
|
|
14
14
|
import {UserFlow, auditGatherSteps} from './user-flow.js';
|
|
@@ -63,9 +63,9 @@ async function legacyNavigation(url, flags = {}, configJSON, userConnection) {
|
|
|
63
63
|
flags.logLevel = flags.logLevel || 'error';
|
|
64
64
|
log.setLevel(flags.logLevel);
|
|
65
65
|
|
|
66
|
-
const
|
|
66
|
+
const resolvedConfig = await LegacyResolvedConfig.fromJson(configJSON, flags);
|
|
67
67
|
const computedCache = new Map();
|
|
68
|
-
const options = {
|
|
68
|
+
const options = {resolvedConfig, computedCache};
|
|
69
69
|
const connection = userConnection || new CriConnection(flags.port, flags.hostname);
|
|
70
70
|
|
|
71
71
|
// kick off a lighthouse run
|
|
@@ -55,15 +55,15 @@ const BASE_ARTIFACT_BLANKS = {
|
|
|
55
55
|
const BASE_ARTIFACT_NAMES = Object.keys(BASE_ARTIFACT_BLANKS);
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
|
-
* @param {
|
|
59
|
-
* @param {
|
|
58
|
+
* @param {LegacyResolvedConfig['passes']} passes
|
|
59
|
+
* @param {LegacyResolvedConfig['audits']} audits
|
|
60
60
|
*/
|
|
61
61
|
function assertValidPasses(passes, audits) {
|
|
62
62
|
if (!Array.isArray(passes)) {
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
const requestedGatherers =
|
|
66
|
+
const requestedGatherers = LegacyResolvedConfig.getGatherersRequestedByAudits(audits);
|
|
67
67
|
// Base artifacts are provided by GatherRunner, so start foundGatherers with them.
|
|
68
68
|
const foundGatherers = new Set(BASE_ARTIFACT_NAMES);
|
|
69
69
|
|
|
@@ -129,15 +129,15 @@ function assertValidGatherer(gathererInstance, gathererName) {
|
|
|
129
129
|
}
|
|
130
130
|
|
|
131
131
|
/**
|
|
132
|
-
* @implements {LH.Config.
|
|
132
|
+
* @implements {LH.Config.LegacyResolvedConfig}
|
|
133
133
|
*/
|
|
134
|
-
class
|
|
134
|
+
class LegacyResolvedConfig {
|
|
135
135
|
/**
|
|
136
136
|
* Resolves the provided config (inherits from extended config, if set), resolves
|
|
137
137
|
* all referenced modules, and validates.
|
|
138
138
|
* @param {LH.Config.Json=} configJSON If not provided, uses the default config.
|
|
139
139
|
* @param {LH.Flags=} flags
|
|
140
|
-
* @return {Promise<
|
|
140
|
+
* @return {Promise<LegacyResolvedConfig>}
|
|
141
141
|
*/
|
|
142
142
|
static async fromJson(configJSON, flags) {
|
|
143
143
|
const status = {msg: 'Create config', id: 'lh:init:config'};
|
|
@@ -161,7 +161,8 @@ class Config {
|
|
|
161
161
|
if (configJSON.extends !== 'lighthouse:default') {
|
|
162
162
|
throw new Error('`lighthouse:default` is the only valid extension method.');
|
|
163
163
|
}
|
|
164
|
-
configJSON =
|
|
164
|
+
configJSON = LegacyResolvedConfig.extendConfigJSON(
|
|
165
|
+
deepCloneConfigJson(legacyDefaultConfig), configJSON);
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
// The directory of the config path, if one was provided.
|
|
@@ -173,15 +174,15 @@ class Config {
|
|
|
173
174
|
const settings = resolveSettings(configJSON.settings || {}, flags);
|
|
174
175
|
|
|
175
176
|
// Augment passes with necessary defaults and require gatherers.
|
|
176
|
-
const passesWithDefaults =
|
|
177
|
-
|
|
178
|
-
const passes = await
|
|
177
|
+
const passesWithDefaults = LegacyResolvedConfig.augmentPassesWithDefaults(configJSON.passes);
|
|
178
|
+
LegacyResolvedConfig.adjustDefaultPassForThrottling(settings, passesWithDefaults);
|
|
179
|
+
const passes = await LegacyResolvedConfig.requireGatherers(passesWithDefaults, configDir);
|
|
179
180
|
|
|
180
|
-
const audits = await
|
|
181
|
+
const audits = await LegacyResolvedConfig.requireAudits(configJSON.audits, configDir);
|
|
181
182
|
|
|
182
|
-
const
|
|
183
|
+
const resolvedConfig = new LegacyResolvedConfig(configJSON, {settings, passes, audits});
|
|
183
184
|
log.timeEnd(status);
|
|
184
|
-
return
|
|
185
|
+
return resolvedConfig;
|
|
185
186
|
}
|
|
186
187
|
|
|
187
188
|
/**
|
|
@@ -202,7 +203,7 @@ class Config {
|
|
|
202
203
|
/** @type {?Record<string, LH.Config.Group>} */
|
|
203
204
|
this.groups = configJSON.groups || null;
|
|
204
205
|
|
|
205
|
-
|
|
206
|
+
LegacyResolvedConfig.filterConfigIfNeeded(this);
|
|
206
207
|
|
|
207
208
|
assertValidPasses(this.passes, this.audits);
|
|
208
209
|
validation.assertValidCategories(this.categories, this.audits, this.groups);
|
|
@@ -308,7 +309,7 @@ class Config {
|
|
|
308
309
|
|
|
309
310
|
/**
|
|
310
311
|
* Filter out any unrequested items from the config, based on requested categories or audits.
|
|
311
|
-
* @param {
|
|
312
|
+
* @param {LegacyResolvedConfig} config
|
|
312
313
|
*/
|
|
313
314
|
static filterConfigIfNeeded(config) {
|
|
314
315
|
const settings = config.settings;
|
|
@@ -317,18 +318,19 @@ class Config {
|
|
|
317
318
|
}
|
|
318
319
|
|
|
319
320
|
// 1. Filter to just the chosen categories/audits
|
|
320
|
-
const {categories, requestedAuditNames} =
|
|
321
|
-
settings);
|
|
321
|
+
const {categories, requestedAuditNames} =
|
|
322
|
+
LegacyResolvedConfig.filterCategoriesAndAudits(config.categories, settings);
|
|
322
323
|
|
|
323
324
|
// 2. Resolve which audits will need to run
|
|
324
325
|
const audits = config.audits && config.audits.filter(auditDefn =>
|
|
325
326
|
requestedAuditNames.has(auditDefn.implementation.meta.id));
|
|
326
327
|
|
|
327
328
|
// 3. Resolve which gatherers will need to run
|
|
328
|
-
const requestedGathererIds =
|
|
329
|
+
const requestedGathererIds = LegacyResolvedConfig.getGatherersRequestedByAudits(audits);
|
|
329
330
|
|
|
330
331
|
// 4. Filter to only the neccessary passes
|
|
331
|
-
const passes =
|
|
332
|
+
const passes =
|
|
333
|
+
LegacyResolvedConfig.generatePassesNeededByGatherers(config.passes, requestedGathererIds);
|
|
332
334
|
|
|
333
335
|
config.categories = categories;
|
|
334
336
|
config.audits = audits;
|
|
@@ -337,9 +339,9 @@ class Config {
|
|
|
337
339
|
|
|
338
340
|
/**
|
|
339
341
|
* Filter out any unrequested categories or audits from the categories object.
|
|
340
|
-
* @param {
|
|
342
|
+
* @param {LegacyResolvedConfig['categories']} oldCategories
|
|
341
343
|
* @param {LH.Config.Settings} settings
|
|
342
|
-
* @return {{categories:
|
|
344
|
+
* @return {{categories: LegacyResolvedConfig['categories'], requestedAuditNames: Set<string>}}
|
|
343
345
|
*/
|
|
344
346
|
static filterCategoriesAndAudits(oldCategories, settings) {
|
|
345
347
|
if (!oldCategories) {
|
|
@@ -350,7 +352,7 @@ class Config {
|
|
|
350
352
|
throw new Error('Cannot set both skipAudits and onlyAudits');
|
|
351
353
|
}
|
|
352
354
|
|
|
353
|
-
/** @type {NonNullable<
|
|
355
|
+
/** @type {NonNullable<LegacyResolvedConfig['categories']>} */
|
|
354
356
|
const categories = {};
|
|
355
357
|
const filterByIncludedCategory = !!settings.onlyCategories;
|
|
356
358
|
const filterByIncludedAudit = !!settings.onlyAudits;
|
|
@@ -424,7 +426,7 @@ class Config {
|
|
|
424
426
|
|
|
425
427
|
/**
|
|
426
428
|
* From some requested audits, return names of all required and optional artifacts
|
|
427
|
-
* @param {
|
|
429
|
+
* @param {LegacyResolvedConfig['audits']} audits
|
|
428
430
|
* @return {Set<string>}
|
|
429
431
|
*/
|
|
430
432
|
static getGatherersRequestedByAudits(audits) {
|
|
@@ -447,9 +449,9 @@ class Config {
|
|
|
447
449
|
|
|
448
450
|
/**
|
|
449
451
|
* Filters to only requested passes and gatherers, returning a new passes array.
|
|
450
|
-
* @param {
|
|
452
|
+
* @param {LegacyResolvedConfig['passes']} passes
|
|
451
453
|
* @param {Set<string>} requestedGatherers
|
|
452
|
-
* @return {
|
|
454
|
+
* @return {LegacyResolvedConfig['passes']}
|
|
453
455
|
*/
|
|
454
456
|
static generatePassesNeededByGatherers(passes, requestedGatherers) {
|
|
455
457
|
if (!passes) {
|
|
@@ -488,7 +490,7 @@ class Config {
|
|
|
488
490
|
* leaving only an array of AuditDefns.
|
|
489
491
|
* @param {LH.Config.Json['audits']} audits
|
|
490
492
|
* @param {string=} configDir
|
|
491
|
-
* @return {Promise<
|
|
493
|
+
* @return {Promise<LegacyResolvedConfig['audits']>}
|
|
492
494
|
*/
|
|
493
495
|
static async requireAudits(audits, configDir) {
|
|
494
496
|
const status = {msg: 'Requiring audits', id: 'lh:config:requireAudits'};
|
|
@@ -504,7 +506,7 @@ class Config {
|
|
|
504
506
|
* provided) using `resolveModulePath`, returning an array of full Passes.
|
|
505
507
|
* @param {?Array<Required<LH.Config.PassJson>>} passes
|
|
506
508
|
* @param {string=} configDir
|
|
507
|
-
* @return {Promise<
|
|
509
|
+
* @return {Promise<LegacyResolvedConfig['passes']>}
|
|
508
510
|
*/
|
|
509
511
|
static async requireGatherers(passes, configDir) {
|
|
510
512
|
if (!passes) {
|
|
@@ -535,4 +537,4 @@ class Config {
|
|
|
535
537
|
}
|
|
536
538
|
}
|
|
537
539
|
|
|
538
|
-
export {
|
|
540
|
+
export {LegacyResolvedConfig};
|
package/core/runner.js
CHANGED
|
@@ -28,18 +28,18 @@ const moduleDir = getModuleDirectory(import.meta);
|
|
|
28
28
|
|
|
29
29
|
/** @typedef {import('./legacy/gather/connections/connection.js').Connection} Connection */
|
|
30
30
|
/** @typedef {import('./lib/arbitrary-equality-map.js').ArbitraryEqualityMap} ArbitraryEqualityMap */
|
|
31
|
-
/** @typedef {LH.Config.
|
|
31
|
+
/** @typedef {LH.Config.LegacyResolvedConfig} Config */
|
|
32
32
|
|
|
33
33
|
class Runner {
|
|
34
34
|
/**
|
|
35
|
-
* @template {LH.Config.
|
|
35
|
+
* @template {LH.Config.LegacyResolvedConfig | LH.Config.ResolvedConfig} TConfig
|
|
36
36
|
* @param {LH.Artifacts} artifacts
|
|
37
|
-
* @param {{
|
|
37
|
+
* @param {{resolvedConfig: TConfig, driverMock?: Driver, computedCache: Map<string, ArbitraryEqualityMap>}} options
|
|
38
38
|
* @return {Promise<LH.RunnerResult|undefined>}
|
|
39
39
|
*/
|
|
40
40
|
static async audit(artifacts, options) {
|
|
41
|
-
const {
|
|
42
|
-
const settings =
|
|
41
|
+
const {resolvedConfig, computedCache} = options;
|
|
42
|
+
const settings = resolvedConfig.settings;
|
|
43
43
|
|
|
44
44
|
try {
|
|
45
45
|
const runnerStatus = {msg: 'Audit phase', id: 'lh:runner:audit'};
|
|
@@ -54,10 +54,10 @@ class Runner {
|
|
|
54
54
|
// Potentially quit early
|
|
55
55
|
if (settings.gatherMode && !settings.auditMode) return;
|
|
56
56
|
|
|
57
|
-
if (!
|
|
57
|
+
if (!resolvedConfig.audits) {
|
|
58
58
|
throw new Error('No audits to evaluate.');
|
|
59
59
|
}
|
|
60
|
-
const auditResultsById = await Runner._runAudits(settings,
|
|
60
|
+
const auditResultsById = await Runner._runAudits(settings, resolvedConfig.audits, artifacts,
|
|
61
61
|
lighthouseRunWarnings, computedCache);
|
|
62
62
|
|
|
63
63
|
// LHR construction phase
|
|
@@ -79,8 +79,8 @@ class Runner {
|
|
|
79
79
|
|
|
80
80
|
/** @type {Record<string, LH.RawIcu<LH.Result.Category>>} */
|
|
81
81
|
let categories = {};
|
|
82
|
-
if (
|
|
83
|
-
categories = ReportScoring.scoreAllCategories(
|
|
82
|
+
if (resolvedConfig.categories) {
|
|
83
|
+
categories = ReportScoring.scoreAllCategories(resolvedConfig.categories, auditResultsById);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
log.timeEnd(resultsStatus);
|
|
@@ -108,7 +108,7 @@ class Runner {
|
|
|
108
108
|
audits: auditResultsById,
|
|
109
109
|
configSettings: settings,
|
|
110
110
|
categories,
|
|
111
|
-
categoryGroups:
|
|
111
|
+
categoryGroups: resolvedConfig.groups || undefined,
|
|
112
112
|
stackPacks: stackPacks.getStackPacks(artifacts.Stacks),
|
|
113
113
|
timing: this._getTiming(artifacts),
|
|
114
114
|
i18n: {
|
|
@@ -142,13 +142,13 @@ class Runner {
|
|
|
142
142
|
* -G and -A will run partial lighthouse pipelines,
|
|
143
143
|
* and -GA will run everything plus save artifacts and lhr to disk.
|
|
144
144
|
*
|
|
145
|
-
* @template {LH.Config.
|
|
146
|
-
* @param {(runnerData: {
|
|
147
|
-
* @param {{
|
|
145
|
+
* @template {LH.Config.LegacyResolvedConfig | LH.Config.ResolvedConfig} TConfig
|
|
146
|
+
* @param {(runnerData: {resolvedConfig: TConfig, driverMock?: Driver}) => Promise<LH.Artifacts>} gatherFn
|
|
147
|
+
* @param {{resolvedConfig: TConfig, driverMock?: Driver, computedCache: Map<string, ArbitraryEqualityMap>}} options
|
|
148
148
|
* @return {Promise<LH.Artifacts>}
|
|
149
149
|
*/
|
|
150
150
|
static async gather(gatherFn, options) {
|
|
151
|
-
const settings = options.
|
|
151
|
+
const settings = options.resolvedConfig.settings;
|
|
152
152
|
|
|
153
153
|
// Either load saved artifacts from disk or from the browser.
|
|
154
154
|
try {
|
|
@@ -170,7 +170,7 @@ class Runner {
|
|
|
170
170
|
log.time(runnerStatus, 'verbose');
|
|
171
171
|
|
|
172
172
|
artifacts = await gatherFn({
|
|
173
|
-
|
|
173
|
+
resolvedConfig: options.resolvedConfig,
|
|
174
174
|
driverMock: options.driverMock,
|
|
175
175
|
});
|
|
176
176
|
|
|
@@ -248,22 +248,22 @@ class Runner {
|
|
|
248
248
|
/**
|
|
249
249
|
* Establish connection, load page and collect all required artifacts
|
|
250
250
|
* @param {string} requestedUrl
|
|
251
|
-
* @param {{
|
|
251
|
+
* @param {{resolvedConfig: Config, computedCache: Map<string, ArbitraryEqualityMap>, driverMock?: Driver}} runnerOpts
|
|
252
252
|
* @param {Connection} connection
|
|
253
253
|
* @return {Promise<LH.Artifacts>}
|
|
254
254
|
*/
|
|
255
255
|
static async _gatherArtifactsFromBrowser(requestedUrl, runnerOpts, connection) {
|
|
256
|
-
if (!runnerOpts.
|
|
256
|
+
if (!runnerOpts.resolvedConfig.passes) {
|
|
257
257
|
throw new Error('No browser artifacts are either provided or requested.');
|
|
258
258
|
}
|
|
259
259
|
const driver = runnerOpts.driverMock || new Driver(connection);
|
|
260
260
|
const gatherOpts = {
|
|
261
261
|
driver,
|
|
262
262
|
requestedUrl,
|
|
263
|
-
settings: runnerOpts.
|
|
263
|
+
settings: runnerOpts.resolvedConfig.settings,
|
|
264
264
|
computedCache: runnerOpts.computedCache,
|
|
265
265
|
};
|
|
266
|
-
const artifacts = await GatherRunner.run(runnerOpts.
|
|
266
|
+
const artifacts = await GatherRunner.run(runnerOpts.resolvedConfig.passes, gatherOpts);
|
|
267
267
|
return artifacts;
|
|
268
268
|
}
|
|
269
269
|
|
package/core/user-flow.js
CHANGED
|
@@ -323,9 +323,9 @@ async function auditGatherSteps(gatherSteps, options) {
|
|
|
323
323
|
// Step specific configs take precedence over a config for the entire flow.
|
|
324
324
|
const configJson = options.config;
|
|
325
325
|
const {gatherMode} = artifacts.GatherContext;
|
|
326
|
-
const {
|
|
326
|
+
const {resolvedConfig} = await initializeConfig(gatherMode, configJson, flags);
|
|
327
327
|
runnerOptions = {
|
|
328
|
-
|
|
328
|
+
resolvedConfig,
|
|
329
329
|
computedCache: new Map(),
|
|
330
330
|
};
|
|
331
331
|
}
|
|
@@ -5286,7 +5286,8 @@ class TopbarFeatures {
|
|
|
5286
5286
|
*/
|
|
5287
5287
|
_setUpCollapseDetailsAfterPrinting() {
|
|
5288
5288
|
// FF and IE implement these old events.
|
|
5289
|
-
|
|
5289
|
+
const supportsOldPrintEvents = 'onbeforeprint' in self;
|
|
5290
|
+
if (supportsOldPrintEvents) {
|
|
5290
5291
|
self.addEventListener('afterprint', this.collapseAllDetails);
|
|
5291
5292
|
} else {
|
|
5292
5293
|
// Note: FF implements both window.onbeforeprint and media listeners. However,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lighthouse",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "9.5.0-dev.
|
|
4
|
+
"version": "9.5.0-dev.20230104",
|
|
5
5
|
"description": "Automated auditing, performance metrics, and best practices for the web.",
|
|
6
6
|
"main": "./core/index.js",
|
|
7
7
|
"bin": {
|
|
@@ -127,8 +127,8 @@
|
|
|
127
127
|
"@types/ws": "^7.0.0",
|
|
128
128
|
"@types/yargs": "^17.0.8",
|
|
129
129
|
"@types/yargs-parser": "^20.2.1",
|
|
130
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
131
|
-
"@typescript-eslint/parser": "^5.
|
|
130
|
+
"@typescript-eslint/eslint-plugin": "^5.48.0",
|
|
131
|
+
"@typescript-eslint/parser": "^5.48.0",
|
|
132
132
|
"acorn": "^8.5.0",
|
|
133
133
|
"angular": "^1.7.4",
|
|
134
134
|
"archiver": "^3.0.0",
|
|
@@ -178,7 +178,7 @@
|
|
|
178
178
|
"terser": "^5.3.8",
|
|
179
179
|
"testdouble": "^3.16.5",
|
|
180
180
|
"typed-query-selector": "^2.6.1",
|
|
181
|
-
"typescript": "^4.
|
|
181
|
+
"typescript": "^4.9.4",
|
|
182
182
|
"wait-for-expect": "^3.0.2",
|
|
183
183
|
"webtreemap-cdt": "^3.2.1"
|
|
184
184
|
},
|
|
@@ -240,7 +240,8 @@ export class TopbarFeatures {
|
|
|
240
240
|
*/
|
|
241
241
|
_setUpCollapseDetailsAfterPrinting() {
|
|
242
242
|
// FF and IE implement these old events.
|
|
243
|
-
|
|
243
|
+
const supportsOldPrintEvents = 'onbeforeprint' in self;
|
|
244
|
+
if (supportsOldPrintEvents) {
|
|
244
245
|
self.addEventListener('afterprint', this.collapseAllDetails);
|
|
245
246
|
} else {
|
|
246
247
|
// Note: FF implements both window.onbeforeprint and media listeners. However,
|
|
@@ -1679,9 +1679,15 @@
|
|
|
1679
1679
|
"core/gather/driver/navigation.js | warningTimeout": {
|
|
1680
1680
|
"message": "The page loaded too slowly to finish within the time limit. Results may be incomplete."
|
|
1681
1681
|
},
|
|
1682
|
+
"core/gather/driver/storage.js | warningCacheTimeout": {
|
|
1683
|
+
"message": "Clearing the browser cache timed out. Try auditing this page again and file a bug if the issue persists."
|
|
1684
|
+
},
|
|
1682
1685
|
"core/gather/driver/storage.js | warningData": {
|
|
1683
1686
|
"message": "{locationCount, plural,\n =1 {There may be stored data affecting loading performance in this location: {locations}. Audit this page in an incognito window to prevent those resources from affecting your scores.}\n other {There may be stored data affecting loading performance in these locations: {locations}. Audit this page in an incognito window to prevent those resources from affecting your scores.}\n }"
|
|
1684
1687
|
},
|
|
1688
|
+
"core/gather/driver/storage.js | warningOriginDataTimeout": {
|
|
1689
|
+
"message": "Clearing the origin data timed out. Try auditing this page again and file a bug if the issue persists."
|
|
1690
|
+
},
|
|
1685
1691
|
"core/lib/bfcache-strings.js | appBanner": {
|
|
1686
1692
|
"message": "Pages that requested an AppBanner are not currently eligible for back/forward cache."
|
|
1687
1693
|
},
|
|
@@ -1679,9 +1679,15 @@
|
|
|
1679
1679
|
"core/gather/driver/navigation.js | warningTimeout": {
|
|
1680
1680
|
"message": "T̂h́ê ṕâǵê ĺôád̂éd̂ t́ôó ŝĺôẃl̂ý t̂ó f̂ín̂íŝh́ ŵít̂h́îń t̂h́ê t́îḿê ĺîḿît́. R̂éŝúl̂t́ŝ ḿâý b̂é îńĉóm̂ṕl̂ét̂é."
|
|
1681
1681
|
},
|
|
1682
|
+
"core/gather/driver/storage.js | warningCacheTimeout": {
|
|
1683
|
+
"message": "Ĉĺêár̂ín̂ǵ t̂h́ê b́r̂óŵśêŕ ĉáĉh́ê t́îḿêd́ ôút̂. T́r̂ý âúd̂ít̂ín̂ǵ t̂h́îś p̂áĝé âǵâín̂ án̂d́ f̂íl̂é â b́ûǵ îf́ t̂h́ê íŝśûé p̂ér̂śîśt̂ś."
|
|
1684
|
+
},
|
|
1682
1685
|
"core/gather/driver/storage.js | warningData": {
|
|
1683
1686
|
"message": "{locationCount, plural,\n =1 {T̂h́êŕê ḿâý b̂é ŝt́ôŕêd́ d̂át̂á âf́f̂éĉt́îńĝ ĺôád̂ín̂ǵ p̂ér̂f́ôŕm̂án̂ćê ín̂ t́ĥíŝ ĺôćât́îón̂: {locations}. Áûd́ît́ t̂h́îś p̂áĝé îń âń îńĉóĝńît́ô ẃîńd̂óŵ t́ô ṕr̂év̂én̂t́ t̂h́ôśê ŕêśôúr̂ćêś f̂ŕôḿ âf́f̂éĉt́îńĝ ýôúr̂ śĉór̂éŝ.}\n other {T́ĥér̂é m̂áŷ b́ê śt̂ór̂éd̂ d́ât́â áf̂f́êćt̂ín̂ǵ l̂óâd́îńĝ ṕêŕf̂ór̂ḿâńĉé îń t̂h́êśê ĺôćât́îón̂ś: {locations}. Âúd̂ít̂ t́ĥíŝ ṕâǵê ín̂ án̂ ín̂ćôǵn̂ít̂ó ŵín̂d́ôẃ t̂ó p̂ŕêv́êńt̂ t́ĥóŝé r̂éŝóûŕĉéŝ f́r̂óm̂ áf̂f́êćt̂ín̂ǵ ŷóûŕ ŝćôŕêś.}\n }"
|
|
1684
1687
|
},
|
|
1688
|
+
"core/gather/driver/storage.js | warningOriginDataTimeout": {
|
|
1689
|
+
"message": "Ĉĺêár̂ín̂ǵ t̂h́ê ór̂íĝín̂ d́ât́â t́îḿêd́ ôút̂. T́r̂ý âúd̂ít̂ín̂ǵ t̂h́îś p̂áĝé âǵâín̂ án̂d́ f̂íl̂é â b́ûǵ îf́ t̂h́ê íŝśûé p̂ér̂śîśt̂ś."
|
|
1690
|
+
},
|
|
1685
1691
|
"core/lib/bfcache-strings.js | appBanner": {
|
|
1686
1692
|
"message": "P̂áĝéŝ t́ĥát̂ ŕêq́ûéŝt́êd́ âń Âṕp̂B́âńn̂ér̂ ár̂é n̂ót̂ ćûŕr̂én̂t́l̂ý êĺîǵîb́l̂é f̂ór̂ b́âćk̂/f́ôŕŵár̂d́ ĉáĉh́ê."
|
|
1687
1693
|
},
|
package/types/config.d.ts
CHANGED
|
@@ -34,9 +34,9 @@ declare module Config {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* The normalized and fully resolved config.
|
|
37
|
+
* The normalized and fully resolved legacy config.
|
|
38
38
|
*/
|
|
39
|
-
interface
|
|
39
|
+
interface LegacyResolvedConfig {
|
|
40
40
|
settings: Settings;
|
|
41
41
|
passes: Pass[] | null;
|
|
42
42
|
audits: AuditDefn[] | null;
|
|
@@ -45,9 +45,9 @@ declare module Config {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
|
-
* The normalized and fully resolved
|
|
48
|
+
* The normalized and fully resolved config.
|
|
49
49
|
*/
|
|
50
|
-
interface
|
|
50
|
+
interface ResolvedConfig {
|
|
51
51
|
settings: Settings;
|
|
52
52
|
artifacts: AnyArtifactDefn[] | null;
|
|
53
53
|
navigations: NavigationDefn[] | null;
|
package/types/gatherer.d.ts
CHANGED