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.
@@ -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
@@ -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<{config: LH.Config.FRConfig, warnings: string[]}>}
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.FRConfig} */
260
- let config = {
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(config);
269
+ const {warnings} = assertValidConfig(resolvedConfig);
270
270
 
271
- config = filterConfigByGatherMode(config, gatherMode);
272
- config = filterConfigByExplicitFilters(config, settings);
271
+ resolvedConfig = filterConfigByGatherMode(resolvedConfig, gatherMode);
272
+ resolvedConfig = filterConfigByExplicitFilters(resolvedConfig, settings);
273
273
 
274
274
  log.timeEnd(status);
275
- return {config, warnings};
275
+ return {resolvedConfig, warnings};
276
276
  }
277
277
 
278
278
  /**
279
- * @param {LH.Config.FRConfig} config
279
+ * @param {LH.Config.ResolvedConfig} resolvedConfig
280
280
  * @return {string}
281
281
  */
282
- function getConfigDisplayString(config) {
283
- /** @type {LH.Config.FRConfig} */
284
- const jsonConfig = JSON.parse(JSON.stringify(config));
282
+ function getConfigDisplayString(resolvedConfig) {
283
+ /** @type {LH.Config.ResolvedConfig} */
284
+ const resolvedConfigCopy = JSON.parse(JSON.stringify(resolvedConfig));
285
285
 
286
- if (jsonConfig.navigations) {
287
- for (const navigation of jsonConfig.navigations) {
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 (jsonConfig.artifacts) {
296
- for (const artifactDefn of jsonConfig.artifacts) {
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 (jsonConfig.audits) {
305
- for (const auditDefn of jsonConfig.audits) {
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(jsonConfig, jsonConfig.settings.locale);
316
+ format.replaceIcuMessages(resolvedConfigCopy, resolvedConfigCopy.settings.locale);
317
317
 
318
- return JSON.stringify(jsonConfig, null, 2);
318
+ return JSON.stringify(resolvedConfigCopy, null, 2);
319
319
  }
320
320
 
321
321
  export {
@@ -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.FRConfig['categories']} allCategories
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.FRConfig['artifacts']} artifacts
59
- * @param {LH.Config.FRConfig['audits']} audits
60
- * @return {LH.Config.FRConfig['artifacts']}
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.FRConfig['artifacts']} artifacts
98
+ * @param {LH.Config.ResolvedConfig['artifacts']} artifacts
99
99
  * @param {LH.Gatherer.GatherMode} mode
100
- * @return {LH.Config.FRConfig['artifacts']}
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.FRConfig['navigations']} navigations
112
+ * @param {LH.Config.ResolvedConfig['navigations']} navigations
113
113
  * @param {Array<LH.Config.AnyArtifactDefn>} availableArtifacts
114
- * @return {LH.Config.FRConfig['navigations']}
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.FRConfig['audits']} audits
136
+ * @param {LH.Config.ResolvedConfig['audits']} audits
137
137
  * @param {Array<LH.Config.AnyArtifactDefn>} availableArtifacts
138
- * @return {LH.Config.FRConfig['audits']}
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.FRConfig['audits']} audits
155
+ * @param {LH.Config.ResolvedConfig['audits']} audits
156
156
  * @param {LH.Gatherer.GatherMode} mode
157
- * @return {LH.Config.FRConfig['audits']}
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.Config['categories']} categories
171
+ * @param {LH.Config.LegacyResolvedConfig['categories']} categories
172
172
  * @param {LH.Gatherer.GatherMode} mode
173
- * @return {LH.Config.Config['categories']}
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.Config['categories']} categories
188
+ * @param {LH.Config.LegacyResolvedConfig['categories']} categories
189
189
  * @param {string[] | null | undefined} onlyCategories
190
- * @return {LH.Config.Config['categories']}
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.Config['categories']} allCategories
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.Config['categories']} categories
222
+ * @param {LH.Config.LegacyResolvedConfig['categories']} categories
223
223
  * @param {Array<LH.Config.AuditDefn>} availableAudits
224
- * @return {LH.Config.Config['categories']}
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.FRConfig} config
260
+ * @param {LH.Config.ResolvedConfig} resolvedConfig
261
261
  * @param {LH.Gatherer.GatherMode} mode
262
- * @return {LH.Config.FRConfig}
262
+ * @return {LH.Config.ResolvedConfig}
263
263
  */
264
- function filterConfigByGatherMode(config, mode) {
265
- const artifacts = filterArtifactsByGatherMode(config.artifacts, mode);
266
- const supportedAudits = filterAuditsByGatherMode(config.audits, mode);
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(config.categories, mode);
268
+ const supportedCategories = filterCategoriesByGatherMode(resolvedConfig.categories, mode);
269
269
  const categories = filterCategoriesByAvailableAudits(supportedCategories, audits || []);
270
270
 
271
271
  return {
272
- ...config,
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.FRConfig} config
283
+ * @param {LH.Config.ResolvedConfig} resolvedConfig
284
284
  * @param {Pick<LH.Config.Settings, 'onlyAudits'|'onlyCategories'|'skipAudits'>} filters
285
- * @return {LH.Config.FRConfig}
285
+ * @return {LH.Config.ResolvedConfig}
286
286
  */
287
- function filterConfigByExplicitFilters(config, filters) {
287
+ function filterConfigByExplicitFilters(resolvedConfig, filters) {
288
288
  const {onlyAudits, onlyCategories, skipAudits} = filters;
289
289
 
290
- warnOnUnknownOnlyCategories(config.categories, onlyCategories);
290
+ warnOnUnknownOnlyCategories(resolvedConfig.categories, onlyCategories);
291
291
 
292
- let baseAuditIds = getAuditIdsInCategories(config.categories, undefined);
292
+ let baseAuditIds = getAuditIdsInCategories(resolvedConfig.categories, undefined);
293
293
  if (onlyCategories) {
294
- baseAuditIds = getAuditIdsInCategories(config.categories, onlyCategories);
294
+ baseAuditIds = getAuditIdsInCategories(resolvedConfig.categories, onlyCategories);
295
295
  } else if (onlyAudits) {
296
296
  baseAuditIds = new Set();
297
- } else if (!config.categories || !Object.keys(config.categories).length) {
298
- baseAuditIds = new Set(config.audits?.map(audit => audit.implementation.meta.id));
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 && config.audits ?
310
- config.audits.filter(audit => auditIdsToKeep.has(audit.implementation.meta.id)) :
311
- config.audits;
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 = filterCategoriesByAvailableAudits(config.categories, audits || []);
313
+ const availableCategories =
314
+ filterCategoriesByAvailableAudits(resolvedConfig.categories, audits || []);
314
315
  const categories = filterCategoriesByExplicitFilters(availableCategories, onlyCategories);
315
- const artifacts = filterArtifactsByAvailableAudits(config.artifacts, audits);
316
- const navigations = filterNavigationsByAvailableArtifacts(config.navigations, artifacts || []);
316
+ const artifacts = filterArtifactsByAvailableAudits(resolvedConfig.artifacts, audits);
317
+ const navigations =
318
+ filterNavigationsByAvailableArtifacts(resolvedConfig.navigations, artifacts || []);
317
319
 
318
320
  return {
319
- ...config,
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.FRConfig['navigations']} navigationsDefn
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.FRConfig['categories']} categories
168
- * @param {LH.Config.FRConfig['audits']} audits
169
- * @param {LH.Config.FRConfig['groups']} groups
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.FRConfig} config
250
+ * @param {LH.Config.ResolvedConfig} resolvedConfig
251
251
  * @return {{warnings: string[]}}
252
252
  */
253
- function assertValidConfig(config) {
254
- const {warnings} = assertValidFRNavigations(config.navigations);
253
+ function assertValidConfig(resolvedConfig) {
254
+ const {warnings} = assertValidFRNavigations(resolvedConfig.navigations);
255
255
 
256
- for (const artifactDefn of config.artifacts || []) {
256
+ for (const artifactDefn of resolvedConfig.artifacts || []) {
257
257
  assertValidFRGatherer(artifactDefn.gatherer);
258
258
  }
259
259
 
260
- for (const auditDefn of config.audits || []) {
260
+ for (const auditDefn of resolvedConfig.audits || []) {
261
261
  assertValidAudit(auditDefn);
262
262
  }
263
263
 
264
- assertValidCategories(config.categories, config.audits, config.groups);
265
- assertValidSettings(config.settings);
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.FRConfig} 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(config, driver, context) {
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: config.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
- // Reset the storage and warn if there appears to be other important data.
82
- const warning = await storage.getImportantStorageWarning(session, url);
83
- if (warning) warnings.push(warning);
84
- await storage.clearDataForOrigin(session, url);
85
- await storage.clearBrowserCaches(session);
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<void>}
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<void>}
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
- // Wipe entire disk cache
112
- await session.sendCommand('Network.clearBrowserCache');
113
- // Toggle 'Disable Cache' to evict the memory cache
114
- await session.sendCommand('Network.setCacheDisabled', {cacheDisabled: true});
115
- await session.sendCommand('Network.setCacheDisabled', {cacheDisabled: false});
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
- log.timeEnd(status);
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.FRConfig} 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, config: LH.Config.FRConfig, requestor: LH.NavigationRequestor}} args
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, config, requestor}) {
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' && !config.settings.skipAboutBlank) {
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(config, driver, {gatherMode: 'navigation'});
56
+ const baseArtifacts = await getBaseArtifacts(resolvedConfig, driver, {gatherMode: 'navigation'});
57
57
 
58
- await prepare.prepareTargetForNavigationMode(driver, config.settings);
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, config}) {
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' && !config.settings.skipAboutBlank) {
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
- config.settings,
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, config, requestor} = navigationContext;
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: config.settings.debugNavigation,
103
- maxWaitForFcp: config.settings.maxWaitForFcp,
104
- maxWaitForLoad: config.settings.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.config.settings.locale;
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.config.settings,
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, config: LH.Config.FRConfig, requestor: LH.NavigationRequestor; baseArtifacts: LH.FRBaseArtifacts, computedCache: NavigationContext['computedCache']}} args
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({driver, page, config, requestor, baseArtifacts, computedCache}) {
257
- if (!config.navigations) throw new Error('No navigations configured');
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 config.navigations) {
273
+ for (const navigation of resolvedConfig.navigations) {
265
274
  const navigationContext = {
266
275
  driver,
267
276
  page,
268
277
  navigation,
269
278
  requestor,
270
- config,
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, config: LH.Config.FRConfig}} args
302
+ * @param {{requestedUrl?: string, driver: Driver, resolvedConfig: LH.Config.ResolvedConfig}} args
294
303
  */
295
- async function _cleanup({requestedUrl, driver, config}) {
296
- const didResetStorage = !config.settings.disableStorageReset && requestedUrl;
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 {config} = await initializeConfig('navigation', options.config, flags);
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 = {config, computedCache};
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
- config,
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 {config} = await initializeConfig('snapshot', options.config, flags);
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 = {config, computedCache};
32
+ const runnerOptions = {resolvedConfig, computedCache};
33
33
  const artifacts = await Runner.gather(
34
34
  async () => {
35
- const baseArtifacts = await getBaseArtifacts(config, driver, {gatherMode: 'snapshot'});
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 = config.artifacts || [];
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: config.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 {config} = await initializeConfig('timespan', options.config, flags);
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 = config.artifacts || [];
32
- const baseArtifacts = await getBaseArtifacts(config, driver, {gatherMode: 'timespan'});
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: config.settings,
43
+ settings: resolvedConfig.settings,
44
44
  };
45
45
 
46
- await prepareTargetForTimespanMode(driver, config.settings);
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 = {config, computedCache};
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 {Config} from './legacy/config/config.js';
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 config = await Config.fromJson(configJSON, flags);
66
+ const resolvedConfig = await LegacyResolvedConfig.fromJson(configJSON, flags);
67
67
  const computedCache = new Map();
68
- const options = {config, computedCache};
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 {Config['passes']} passes
59
- * @param {Config['audits']} audits
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 = Config.getGatherersRequestedByAudits(audits);
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.Config}
132
+ * @implements {LH.Config.LegacyResolvedConfig}
133
133
  */
134
- class Config {
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<Config>}
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 = Config.extendConfigJSON(deepCloneConfigJson(legacyDefaultConfig), 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 = Config.augmentPassesWithDefaults(configJSON.passes);
177
- Config.adjustDefaultPassForThrottling(settings, passesWithDefaults);
178
- const passes = await Config.requireGatherers(passesWithDefaults, configDir);
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 Config.requireAudits(configJSON.audits, configDir);
181
+ const audits = await LegacyResolvedConfig.requireAudits(configJSON.audits, configDir);
181
182
 
182
- const config = new Config(configJSON, {settings, passes, audits});
183
+ const resolvedConfig = new LegacyResolvedConfig(configJSON, {settings, passes, audits});
183
184
  log.timeEnd(status);
184
- return config;
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
- Config.filterConfigIfNeeded(this);
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 {Config} config
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} = Config.filterCategoriesAndAudits(config.categories,
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 = Config.getGatherersRequestedByAudits(audits);
329
+ const requestedGathererIds = LegacyResolvedConfig.getGatherersRequestedByAudits(audits);
329
330
 
330
331
  // 4. Filter to only the neccessary passes
331
- const passes = Config.generatePassesNeededByGatherers(config.passes, requestedGathererIds);
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 {Config['categories']} oldCategories
342
+ * @param {LegacyResolvedConfig['categories']} oldCategories
341
343
  * @param {LH.Config.Settings} settings
342
- * @return {{categories: Config['categories'], requestedAuditNames: Set<string>}}
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<Config['categories']>} */
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 {Config['audits']} audits
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 {Config['passes']} passes
452
+ * @param {LegacyResolvedConfig['passes']} passes
451
453
  * @param {Set<string>} requestedGatherers
452
- * @return {Config['passes']}
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<Config['audits']>}
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<Config['passes']>}
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 {Config};
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.Config} Config */
31
+ /** @typedef {LH.Config.LegacyResolvedConfig} Config */
32
32
 
33
33
  class Runner {
34
34
  /**
35
- * @template {LH.Config.Config | LH.Config.FRConfig} TConfig
35
+ * @template {LH.Config.LegacyResolvedConfig | LH.Config.ResolvedConfig} TConfig
36
36
  * @param {LH.Artifacts} artifacts
37
- * @param {{config: TConfig, driverMock?: Driver, computedCache: Map<string, ArbitraryEqualityMap>}} options
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 {config, computedCache} = options;
42
- const settings = config.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 (!config.audits) {
57
+ if (!resolvedConfig.audits) {
58
58
  throw new Error('No audits to evaluate.');
59
59
  }
60
- const auditResultsById = await Runner._runAudits(settings, config.audits, artifacts,
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 (config.categories) {
83
- categories = ReportScoring.scoreAllCategories(config.categories, auditResultsById);
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: config.groups || undefined,
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.Config | LH.Config.FRConfig} TConfig
146
- * @param {(runnerData: {config: TConfig, driverMock?: Driver}) => Promise<LH.Artifacts>} gatherFn
147
- * @param {{config: TConfig, driverMock?: Driver, computedCache: Map<string, ArbitraryEqualityMap>}} options
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.config.settings;
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
- config: options.config,
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 {{config: Config, computedCache: Map<string, ArbitraryEqualityMap>, driverMock?: Driver}} runnerOpts
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.config.passes) {
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.config.settings,
263
+ settings: runnerOpts.resolvedConfig.settings,
264
264
  computedCache: runnerOpts.computedCache,
265
265
  };
266
- const artifacts = await GatherRunner.run(runnerOpts.config.passes, gatherOpts);
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 {config} = await initializeConfig(gatherMode, configJson, flags);
326
+ const {resolvedConfig} = await initializeConfig(gatherMode, configJson, flags);
327
327
  runnerOptions = {
328
- config,
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
- if ('onbeforeprint' in self) {
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.20230102",
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.27.1",
131
- "@typescript-eslint/parser": "^5.27.1",
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.7.3",
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
- if ('onbeforeprint' in self) {
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 Config {
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 Fraggle Rock config.
48
+ * The normalized and fully resolved config.
49
49
  */
50
- interface FRConfig {
50
+ interface ResolvedConfig {
51
51
  settings: Settings;
52
52
  artifacts: AnyArtifactDefn[] | null;
53
53
  navigations: NavigationDefn[] | null;
@@ -67,7 +67,7 @@ declare module Gatherer {
67
67
  interface FRGatherResult {
68
68
  artifacts: Artifacts;
69
69
  runnerOptions: {
70
- config: Config.FRConfig;
70
+ resolvedConfig: Config.ResolvedConfig;
71
71
  computedCache: Map<string, ArbitraryEqualityMap>
72
72
  }
73
73
  }