lighthouse 8.6.0-dev.20211028 → 8.6.0-dev.20211101

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.
Files changed (102) hide show
  1. package/dist/report/flow.js +7 -7
  2. package/dist/report/standalone.js +7 -7
  3. package/flow-report/src/app.tsx +10 -11
  4. package/flow-report/src/common.tsx +11 -5
  5. package/flow-report/src/header.tsx +3 -3
  6. package/flow-report/src/sidebar/flow.tsx +3 -3
  7. package/flow-report/src/sidebar/sidebar.tsx +3 -3
  8. package/flow-report/src/summary/category.tsx +2 -2
  9. package/flow-report/src/util.ts +12 -12
  10. package/flow-report/src/wrappers/report.tsx +11 -6
  11. package/flow-report/test/common-test.tsx +25 -10
  12. package/flow-report/test/flow-report-pptr-test.ts +46 -0
  13. package/flow-report/test/header-test.tsx +6 -6
  14. package/flow-report/test/summary/category-test.tsx +5 -5
  15. package/flow-report/test/util-test.tsx +32 -11
  16. package/jest.config.js +1 -0
  17. package/lighthouse-cli/test/smokehouse/lighthouse-runners/bundle.js +4 -2
  18. package/lighthouse-cli/test/smokehouse/smokehouse.js +1 -1
  19. package/lighthouse-core/audits/errors-in-console.js +0 -2
  20. package/lighthouse-core/audits/image-aspect-ratio.js +1 -2
  21. package/lighthouse-core/audits/image-size-responsive.js +4 -5
  22. package/lighthouse-core/audits/unsized-images.js +1 -1
  23. package/lighthouse-core/computed/image-records.js +4 -3
  24. package/lighthouse-core/computed/metrics/lantern-total-blocking-time.js +3 -4
  25. package/lighthouse-core/computed/metrics/tbt-utils.js +57 -0
  26. package/lighthouse-core/computed/metrics/total-blocking-time.js +3 -53
  27. package/lighthouse-core/config/config-helpers.js +20 -10
  28. package/lighthouse-core/config/default-config.js +59 -56
  29. package/lighthouse-core/fraggle-rock/config/default-config.js +1 -4
  30. package/lighthouse-core/fraggle-rock/gather/base-gatherer.js +6 -1
  31. package/lighthouse-core/gather/driver/storage.js +0 -1
  32. package/lighthouse-core/gather/gatherers/dobetterweb/response-compression.js +1 -0
  33. package/lighthouse-core/gather/gatherers/image-elements.js +0 -3
  34. package/lighthouse-core/lib/asset-saver.js +4 -1
  35. package/lighthouse-core/lib/lh-env.js +2 -0
  36. package/lighthouse-core/lib/tappable-rects.js +8 -15
  37. package/lighthouse-core/runner.js +1 -1
  38. package/lighthouse-core/util-commonjs.js +1 -2
  39. package/package.json +10 -7
  40. package/report/clients/standalone.js +0 -2
  41. package/report/renderer/element-screenshot-renderer.js +2 -2
  42. package/report/renderer/performance-category-renderer.js +20 -5
  43. package/report/renderer/util.js +1 -2
  44. package/report/test/renderer/performance-category-renderer-test.js +34 -8
  45. package/report/test/renderer/report-renderer-test.js +1 -1
  46. package/report/test/renderer/report-ui-features-test.js +3 -0
  47. package/report/test/renderer/util-test.js +13 -31
  48. package/shared/localization/format.js +9 -4
  49. package/shared/localization/locales/ar-XB.json +0 -12
  50. package/shared/localization/locales/ar.json +0 -12
  51. package/shared/localization/locales/bg.json +0 -12
  52. package/shared/localization/locales/ca.json +0 -12
  53. package/shared/localization/locales/cs.json +0 -12
  54. package/shared/localization/locales/da.json +0 -12
  55. package/shared/localization/locales/de.json +0 -12
  56. package/shared/localization/locales/el.json +0 -12
  57. package/shared/localization/locales/en-GB.json +0 -12
  58. package/shared/localization/locales/en-US.json +1 -13
  59. package/shared/localization/locales/en-XA.json +0 -12
  60. package/shared/localization/locales/en-XL.json +1 -13
  61. package/shared/localization/locales/es-419.json +0 -12
  62. package/shared/localization/locales/es.json +0 -12
  63. package/shared/localization/locales/fi.json +0 -12
  64. package/shared/localization/locales/fil.json +0 -12
  65. package/shared/localization/locales/fr.json +0 -12
  66. package/shared/localization/locales/he.json +0 -12
  67. package/shared/localization/locales/hi.json +0 -12
  68. package/shared/localization/locales/hr.json +0 -12
  69. package/shared/localization/locales/hu.json +0 -12
  70. package/shared/localization/locales/id.json +0 -12
  71. package/shared/localization/locales/it.json +0 -12
  72. package/shared/localization/locales/ja.json +0 -12
  73. package/shared/localization/locales/ko.json +0 -12
  74. package/shared/localization/locales/lt.json +0 -12
  75. package/shared/localization/locales/lv.json +0 -12
  76. package/shared/localization/locales/nl.json +0 -12
  77. package/shared/localization/locales/no.json +0 -12
  78. package/shared/localization/locales/pl.json +0 -12
  79. package/shared/localization/locales/pt-PT.json +0 -12
  80. package/shared/localization/locales/pt.json +0 -12
  81. package/shared/localization/locales/ro.json +0 -12
  82. package/shared/localization/locales/ru.json +0 -12
  83. package/shared/localization/locales/sk.json +0 -12
  84. package/shared/localization/locales/sl.json +0 -12
  85. package/shared/localization/locales/sr-Latn.json +0 -12
  86. package/shared/localization/locales/sr.json +0 -12
  87. package/shared/localization/locales/sv.json +0 -12
  88. package/shared/localization/locales/ta.json +0 -12
  89. package/shared/localization/locales/te.json +0 -12
  90. package/shared/localization/locales/th.json +0 -12
  91. package/shared/localization/locales/tr.json +0 -12
  92. package/shared/localization/locales/uk.json +0 -12
  93. package/shared/localization/locales/vi.json +0 -12
  94. package/shared/localization/locales/zh-HK.json +0 -12
  95. package/shared/localization/locales/zh-TW.json +0 -12
  96. package/shared/localization/locales/zh.json +0 -12
  97. package/third-party/chromium-synchronization/installability-errors-test.js +2 -0
  98. package/types/artifacts.d.ts +5 -4
  99. package/types/lhr/flow.d.ts +3 -2
  100. package/types/rollup-plugin-postprocess.d.ts +10 -0
  101. package/lighthouse-core/audits/dobetterweb/appcache-manifest.js +0 -67
  102. package/lighthouse-core/gather/gatherers/dobetterweb/appcache.js +0 -34
@@ -5,6 +5,7 @@
5
5
  */
6
6
  'use strict';
7
7
 
8
+ const URL = require('../lib/url-shim.js');
8
9
  const makeComputedArtifact = require('./computed-artifact.js');
9
10
 
10
11
  class ImageRecords {
@@ -28,12 +29,12 @@ class ImageRecords {
28
29
 
29
30
  /**
30
31
  * @param {{ImageElements: LH.Artifacts['ImageElements'], networkRecords: LH.Artifacts.NetworkRequest[]}} data
31
- * @return {Promise<LH.Artifacts.ImageElement[]>}
32
+ * @return {Promise<LH.Artifacts.ImageElementRecord[]>}
32
33
  */
33
34
  static async compute_(data) {
34
35
  const indexedNetworkRecords = ImageRecords.indexNetworkRecords(data.networkRecords);
35
36
 
36
- /** @type {LH.Artifacts.ImageElement[]} */
37
+ /** @type {LH.Artifacts.ImageElementRecord[]} */
37
38
  const imageRecords = [];
38
39
 
39
40
  for (const element of data.ImageElements) {
@@ -43,7 +44,7 @@ class ImageRecords {
43
44
  // Don't change the guessed mime type if no mime type was found.
44
45
  imageRecords.push({
45
46
  ...element,
46
- mimeType: mimeType ? mimeType : element.mimeType,
47
+ mimeType: mimeType ? mimeType : URL.guessMimeType(element.src),
47
48
  });
48
49
  }
49
50
 
@@ -10,6 +10,7 @@ const LanternMetric = require('./lantern-metric.js');
10
10
  const BaseNode = require('../../lib/dependency-graph/base-node.js');
11
11
  const LanternFirstContentfulPaint = require('./lantern-first-contentful-paint.js');
12
12
  const LanternInteractive = require('./lantern-interactive.js');
13
+ const {BLOCKING_TIME_THRESHOLD, calculateSumOfBlockingTime} = require('./tbt-utils.js');
13
14
 
14
15
  /** @typedef {BaseNode.Node} Node */
15
16
 
@@ -66,9 +67,7 @@ class LanternTotalBlockingTime extends LanternMetric {
66
67
  ? extras.interactiveResult.optimisticEstimate.timeInMs
67
68
  : extras.interactiveResult.pessimisticEstimate.timeInMs;
68
69
 
69
- // Require here to resolve circular dependency.
70
- const TotalBlockingTime = require('./total-blocking-time.js');
71
- const minDurationMs = TotalBlockingTime.BLOCKING_TIME_THRESHOLD;
70
+ const minDurationMs = BLOCKING_TIME_THRESHOLD;
72
71
 
73
72
  const events = LanternTotalBlockingTime.getTopLevelEvents(
74
73
  simulation.nodeTimings,
@@ -76,7 +75,7 @@ class LanternTotalBlockingTime extends LanternMetric {
76
75
  );
77
76
 
78
77
  return {
79
- timeInMs: TotalBlockingTime.calculateSumOfBlockingTime(
78
+ timeInMs: calculateSumOfBlockingTime(
80
79
  events,
81
80
  fcpTimeInMs,
82
81
  interactiveTimeMs
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @license Copyright 2021 The Lighthouse Authors. All Rights Reserved.
3
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
4
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
5
+ */
6
+ 'use strict';
7
+
8
+ const BLOCKING_TIME_THRESHOLD = 50;
9
+
10
+ /**
11
+ * @param {Array<{start: number, end: number, duration: number}>} topLevelEvents
12
+ * @param {number} startTimeMs
13
+ * @param {number} endTimeMs
14
+ * @return {number}
15
+ */
16
+ function calculateSumOfBlockingTime(topLevelEvents, startTimeMs, endTimeMs) {
17
+ if (endTimeMs <= startTimeMs) return 0;
18
+
19
+ const threshold = BLOCKING_TIME_THRESHOLD;
20
+ let sumBlockingTime = 0;
21
+ for (const event of topLevelEvents) {
22
+ // Early exit for small tasks, which should far outnumber long tasks.
23
+ if (event.duration < threshold) continue;
24
+
25
+ // We only want to consider tasks that fall in our time range (FCP and TTI for navigations).
26
+ // FCP is picked as the lower bound because there is little risk of user input happening
27
+ // before FCP so Long Queuing Qelay regions do not harm user experience. Developers should be
28
+ // optimizing to reach FCP as fast as possible without having to worry about task lengths.
29
+ if (event.end < startTimeMs) continue;
30
+
31
+ // TTI is picked as the upper bound because we want a well defined end point for page load.
32
+ if (event.start > endTimeMs) continue;
33
+
34
+ // We first perform the clipping, and then calculate Blocking Region. So if we have a 150ms
35
+ // task [0, 150] and FCP happens midway at 50ms, we first clip the task to [50, 150], and then
36
+ // calculate the Blocking Region to be [100, 150]. The rational here is that tasks before FCP
37
+ // are unimportant, so we care whether the main thread is busy more than 50ms at a time only
38
+ // after FCP.
39
+ const clippedStart = Math.max(event.start, startTimeMs);
40
+ const clippedEnd = Math.min(event.end, endTimeMs);
41
+ const clippedDuration = clippedEnd - clippedStart;
42
+ if (clippedDuration < threshold) continue;
43
+
44
+ // The duration of the task beyond 50ms at the beginning is considered the Blocking Region.
45
+ // Example:
46
+ // [ 250ms Task ]
47
+ // | First 50ms | Blocking Region (200ms) |
48
+ sumBlockingTime += clippedDuration - threshold;
49
+ }
50
+
51
+ return sumBlockingTime;
52
+ }
53
+
54
+ module.exports = {
55
+ BLOCKING_TIME_THRESHOLD,
56
+ calculateSumOfBlockingTime,
57
+ };
@@ -10,6 +10,7 @@ const ComputedMetric = require('./metric.js');
10
10
  const TraceProcessor = require('../../lib/tracehouse/trace-processor.js');
11
11
  const LanternTotalBlockingTime = require('./lantern-total-blocking-time.js');
12
12
  const TimetoInteractive = require('./interactive.js');
13
+ const {calculateSumOfBlockingTime} = require('./tbt-utils.js');
13
14
 
14
15
  /**
15
16
  * @fileoverview This audit determines Total Blocking Time.
@@ -25,57 +26,6 @@ const TimetoInteractive = require('./interactive.js');
25
26
  * to smaller improvements to main thread responsiveness.
26
27
  */
27
28
  class TotalBlockingTime extends ComputedMetric {
28
- /**
29
- * @return {number}
30
- */
31
- static get BLOCKING_TIME_THRESHOLD() {
32
- return 50;
33
- }
34
-
35
- /**
36
- * @param {Array<{start: number, end: number, duration: number}>} topLevelEvents
37
- * @param {number} startTimeMs
38
- * @param {number} endTimeMs
39
- * @return {number}
40
- */
41
- static calculateSumOfBlockingTime(topLevelEvents, startTimeMs, endTimeMs) {
42
- if (endTimeMs <= startTimeMs) return 0;
43
-
44
- const threshold = TotalBlockingTime.BLOCKING_TIME_THRESHOLD;
45
- let sumBlockingTime = 0;
46
- for (const event of topLevelEvents) {
47
- // Early exit for small tasks, which should far outnumber long tasks.
48
- if (event.duration < threshold) continue;
49
-
50
- // We only want to consider tasks that fall in our time range (FCP and TTI for navigations).
51
- // FCP is picked as the lower bound because there is little risk of user input happening
52
- // before FCP so Long Queuing Qelay regions do not harm user experience. Developers should be
53
- // optimizing to reach FCP as fast as possible without having to worry about task lengths.
54
- if (event.end < startTimeMs) continue;
55
-
56
- // TTI is picked as the upper bound because we want a well defined end point for page load.
57
- if (event.start > endTimeMs) continue;
58
-
59
- // We first perform the clipping, and then calculate Blocking Region. So if we have a 150ms
60
- // task [0, 150] and FCP happens midway at 50ms, we first clip the task to [50, 150], and then
61
- // calculate the Blocking Region to be [100, 150]. The rational here is that tasks before FCP
62
- // are unimportant, so we care whether the main thread is busy more than 50ms at a time only
63
- // after FCP.
64
- const clippedStart = Math.max(event.start, startTimeMs);
65
- const clippedEnd = Math.min(event.end, endTimeMs);
66
- const clippedDuration = clippedEnd - clippedStart;
67
- if (clippedDuration < threshold) continue;
68
-
69
- // The duration of the task beyond 50ms at the beginning is considered the Blocking Region.
70
- // Example:
71
- // [ 250ms Task ]
72
- // | First 50ms | Blocking Region (200ms) |
73
- sumBlockingTime += clippedDuration - threshold;
74
- }
75
-
76
- return sumBlockingTime;
77
- }
78
-
79
29
  /**
80
30
  * @param {LH.Artifacts.MetricComputationData} data
81
31
  * @param {LH.Artifacts.ComputedContext} context
@@ -100,7 +50,7 @@ class TotalBlockingTime extends ComputedMetric {
100
50
  const interactiveTimeMs = (await TimetoInteractive.request(metricData, context)).timing;
101
51
 
102
52
  return {
103
- timing: TotalBlockingTime.calculateSumOfBlockingTime(
53
+ timing: calculateSumOfBlockingTime(
104
54
  events,
105
55
  firstContentfulPaint,
106
56
  interactiveTimeMs
@@ -108,7 +58,7 @@ class TotalBlockingTime extends ComputedMetric {
108
58
  };
109
59
  } else {
110
60
  return {
111
- timing: TotalBlockingTime.calculateSumOfBlockingTime(
61
+ timing: calculateSumOfBlockingTime(
112
62
  events,
113
63
  0,
114
64
  data.processedTrace.timestamps.traceEnd
@@ -203,6 +203,18 @@ function expandAuditShorthand(audit) {
203
203
  }
204
204
  }
205
205
 
206
+ /** @type {Map<string, any>} */
207
+ const bundledModules = new Map(/* BUILD_REPLACE_BUNDLED_MODULES */);
208
+
209
+ /**
210
+ * Wraps `require` with an entrypoint for bundled dynamic modules.
211
+ * See build-bundle.js
212
+ * @param {string} requirePath
213
+ */
214
+ function requireWrapper(requirePath) {
215
+ return bundledModules.get(requirePath) || require(requirePath);
216
+ }
217
+
206
218
  /**
207
219
  * @param {string} gathererPath
208
220
  * @param {Array<string>} coreGathererList
@@ -218,7 +230,7 @@ function requireGatherer(gathererPath, coreGathererList, configDir) {
218
230
  requirePath = resolveModulePath(gathererPath, configDir, 'gatherer');
219
231
  }
220
232
 
221
- const GathererClass = /** @type {GathererConstructor} */ (require(requirePath));
233
+ const GathererClass = /** @type {GathererConstructor} */ (requireWrapper(requirePath));
222
234
 
223
235
  return {
224
236
  instance: new GathererClass(),
@@ -228,14 +240,13 @@ function requireGatherer(gathererPath, coreGathererList, configDir) {
228
240
  }
229
241
 
230
242
  /**
231
- *
232
243
  * @param {string} auditPath
233
244
  * @param {Array<string>} coreAuditList
234
245
  * @param {string=} configDir
235
246
  * @return {LH.Config.AuditDefn['implementation']}
236
247
  */
237
248
  function requireAudit(auditPath, coreAuditList, configDir) {
238
- // See if the audit is a Lighthouse core audit.
249
+ // See if the audit is a Lighthouse core audit.
239
250
  const auditPathJs = `${auditPath}.js`;
240
251
  const coreAudit = coreAuditList.find(a => a === auditPathJs);
241
252
  let requirePath = `../audits/${auditPath}`;
@@ -244,14 +255,14 @@ function requireAudit(auditPath, coreAuditList, configDir) {
244
255
  // This is for pubads bundling.
245
256
  requirePath = auditPath;
246
257
  } else {
247
- // Otherwise, attempt to find it elsewhere. This throws if not found.
258
+ // Otherwise, attempt to find it elsewhere. This throws if not found.
248
259
  const absolutePath = resolveModulePath(auditPath, configDir, 'audit');
249
260
  // Use a relative path so bundler can easily expose it.
250
261
  requirePath = path.relative(__dirname, absolutePath);
251
262
  }
252
263
  }
253
264
 
254
- return require(requirePath);
265
+ return requireWrapper(requirePath);
255
266
  }
256
267
 
257
268
  /**
@@ -313,7 +324,6 @@ function resolveSettings(settingsJson = {}, overrides = undefined) {
313
324
  return settingsWithFlags;
314
325
  }
315
326
 
316
-
317
327
  /**
318
328
  * @param {LH.Config.Json} configJSON
319
329
  * @param {string | undefined} configDir
@@ -332,7 +342,7 @@ function mergePlugins(configJSON, configDir, flags) {
332
342
  const pluginPath = isBundledEnvironment() ?
333
343
  pluginName :
334
344
  resolveModulePath(pluginName, configDir, 'plugin');
335
- const rawPluginJson = require(pluginPath);
345
+ const rawPluginJson = requireWrapper(pluginPath);
336
346
  const pluginJson = ConfigPlugin.parsePlugin(rawPluginJson, pluginName);
337
347
 
338
348
  configJSON = mergeConfigFragment(configJSON, pluginJson);
@@ -569,12 +579,12 @@ function deepCloneConfigJson(json) {
569
579
  module.exports = {
570
580
  deepClone,
571
581
  deepCloneConfigJson,
572
- mergeOptionsOfItems,
573
582
  mergeConfigFragment,
574
583
  mergeConfigFragmentArrayByKey,
584
+ mergeOptionsOfItems,
575
585
  mergePlugins,
576
- resolveSettings,
577
- resolveGathererToDefn,
578
586
  resolveAuditsToDefns,
587
+ resolveGathererToDefn,
579
588
  resolveModulePath,
589
+ resolveSettings,
580
590
  };
@@ -96,7 +96,7 @@ const UIStrings = {
96
96
  /** Description of the navigation section within the Search Engine Optimization (SEO) category. Within this section are audits with descriptive titles that highlight ways to make a website accessible to search engine crawlers. */
97
97
  seoCrawlingGroupDescription: 'To appear in search results, crawlers need access to your app.',
98
98
  /** Title of the Progressive Web Application (PWA) category of audits. This is displayed at the top of a list of audits focused on topics related to whether or not a site is a progressive web app, e.g. responds offline, uses a service worker, is on https, etc. Also used as a label of a score gauge. */
99
- pwaCategoryTitle: 'Progressive Web App',
99
+ pwaCategoryTitle: 'PWA',
100
100
  /** Description of the Progressive Web Application (PWA) category. This is displayed at the top of a list of audits focused on topics related to whether or not a site is a progressive web app, e.g. responds offline, uses a service worker, is on https, etc. No character length limits. 'Learn More' becomes link text to additional documentation. */
101
101
  pwaCategoryDescription: 'These checks validate the aspects of a Progressive Web App. ' +
102
102
  '[Learn more](https://developers.google.com/web/progressive-web-apps/checklist).',
@@ -147,7 +147,6 @@ const defaultConfig = {
147
147
  'form-elements',
148
148
  'main-document-content',
149
149
  'global-listeners',
150
- 'dobetterweb/appcache',
151
150
  'dobetterweb/doctype',
152
151
  'dobetterweb/domstats',
153
152
  'dobetterweb/optimized-images',
@@ -301,7 +300,6 @@ const defaultConfig = {
301
300
  'byte-efficiency/efficient-animated-content',
302
301
  'byte-efficiency/duplicated-javascript',
303
302
  'byte-efficiency/legacy-javascript',
304
- 'dobetterweb/appcache-manifest',
305
303
  'dobetterweb/doctype',
306
304
  'dobetterweb/charset',
307
305
  'dobetterweb/dom-size',
@@ -407,6 +405,8 @@ const defaultConfig = {
407
405
  'best-practices-general': {
408
406
  title: str_(UIStrings.bestPracticesGeneralGroupTitle),
409
407
  },
408
+ // Group for audits that should not be displayed.
409
+ 'hidden': {title: ''},
410
410
  },
411
411
  categories: {
412
412
  'performance': {
@@ -420,61 +420,65 @@ const defaultConfig = {
420
420
  {id: 'total-blocking-time', weight: 30, group: 'metrics', acronym: 'TBT', relevantAudits: m2a.tbtRelevantAudits},
421
421
  {id: 'cumulative-layout-shift', weight: 15, group: 'metrics', acronym: 'CLS', relevantAudits: m2a.clsRelevantAudits},
422
422
 
423
- // These are our "invisible" metrics. Not displayed, but still in the LHR
424
- {id: 'max-potential-fid', weight: 0},
425
- {id: 'first-meaningful-paint', weight: 0, acronym: 'FMP'},
423
+ // These are our "invisible" metrics. Not displayed, but still in the LHR.
424
+ {id: 'max-potential-fid', weight: 0, group: 'hidden'},
425
+ {id: 'first-meaningful-paint', weight: 0, acronym: 'FMP', group: 'hidden'},
426
426
 
427
- {id: 'render-blocking-resources', weight: 0, group: 'load-opportunities'},
428
- {id: 'uses-responsive-images', weight: 0, group: 'load-opportunities'},
429
- {id: 'offscreen-images', weight: 0, group: 'load-opportunities'},
430
- {id: 'unminified-css', weight: 0, group: 'load-opportunities'},
431
- {id: 'unminified-javascript', weight: 0, group: 'load-opportunities'},
432
- {id: 'unused-css-rules', weight: 0, group: 'load-opportunities'},
433
- {id: 'unused-javascript', weight: 0, group: 'load-opportunities'},
434
- {id: 'uses-optimized-images', weight: 0, group: 'load-opportunities'},
435
- {id: 'modern-image-formats', weight: 0, group: 'load-opportunities'},
436
- {id: 'uses-text-compression', weight: 0, group: 'load-opportunities'},
437
- {id: 'uses-rel-preconnect', weight: 0, group: 'load-opportunities'},
438
- {id: 'server-response-time', weight: 0, group: 'load-opportunities'},
439
- {id: 'redirects', weight: 0, group: 'load-opportunities'},
440
- {id: 'uses-rel-preload', weight: 0, group: 'load-opportunities'},
441
- {id: 'uses-http2', weight: 0, group: 'load-opportunities'},
442
- {id: 'efficient-animated-content', weight: 0, group: 'load-opportunities'},
443
- {id: 'duplicated-javascript', weight: 0, group: 'load-opportunities'},
444
- {id: 'legacy-javascript', weight: 0, group: 'load-opportunities'},
445
- {id: 'preload-lcp-image', weight: 0, group: 'load-opportunities'},
446
- {id: 'total-byte-weight', weight: 0, group: 'diagnostics'},
447
- {id: 'uses-long-cache-ttl', weight: 0, group: 'diagnostics'},
448
- {id: 'dom-size', weight: 0, group: 'diagnostics'},
449
- {id: 'critical-request-chains', weight: 0, group: 'diagnostics'},
450
- {id: 'user-timings', weight: 0, group: 'diagnostics'},
451
- {id: 'bootup-time', weight: 0, group: 'diagnostics'},
452
- {id: 'mainthread-work-breakdown', weight: 0, group: 'diagnostics'},
453
- {id: 'font-display', weight: 0, group: 'diagnostics'},
427
+ // These audits will be put in "load-opportunities" or "diagnostics" based on their details type.
428
+ {id: 'render-blocking-resources', weight: 0},
429
+ {id: 'uses-responsive-images', weight: 0},
430
+ {id: 'offscreen-images', weight: 0},
431
+ {id: 'unminified-css', weight: 0},
432
+ {id: 'unminified-javascript', weight: 0},
433
+ {id: 'unused-css-rules', weight: 0},
434
+ {id: 'unused-javascript', weight: 0},
435
+ {id: 'uses-optimized-images', weight: 0},
436
+ {id: 'modern-image-formats', weight: 0},
437
+ {id: 'uses-text-compression', weight: 0},
438
+ {id: 'uses-rel-preconnect', weight: 0},
439
+ {id: 'server-response-time', weight: 0},
440
+ {id: 'redirects', weight: 0},
441
+ {id: 'uses-rel-preload', weight: 0},
442
+ {id: 'uses-http2', weight: 0},
443
+ {id: 'efficient-animated-content', weight: 0},
444
+ {id: 'duplicated-javascript', weight: 0},
445
+ {id: 'legacy-javascript', weight: 0},
446
+ {id: 'preload-lcp-image', weight: 0},
447
+ {id: 'total-byte-weight', weight: 0},
448
+ {id: 'uses-long-cache-ttl', weight: 0},
449
+ {id: 'dom-size', weight: 0},
450
+ {id: 'critical-request-chains', weight: 0},
451
+ {id: 'user-timings', weight: 0},
452
+ {id: 'bootup-time', weight: 0},
453
+ {id: 'mainthread-work-breakdown', weight: 0},
454
+ {id: 'font-display', weight: 0},
455
+ {id: 'resource-summary', weight: 0},
456
+ {id: 'third-party-summary', weight: 0},
457
+ {id: 'third-party-facades', weight: 0},
458
+ {id: 'largest-contentful-paint-element', weight: 0},
459
+ {id: 'lcp-lazy-loaded', weight: 0},
460
+ {id: 'layout-shift-elements', weight: 0},
461
+ {id: 'uses-passive-event-listeners', weight: 0},
462
+ {id: 'no-document-write', weight: 0},
463
+ {id: 'long-tasks', weight: 0},
464
+ {id: 'non-composited-animations', weight: 0},
465
+ {id: 'unsized-images', weight: 0},
466
+ {id: 'viewport', weight: 0},
467
+
468
+ // Budget audits.
454
469
  {id: 'performance-budget', weight: 0, group: 'budgets'},
455
470
  {id: 'timing-budget', weight: 0, group: 'budgets'},
456
- {id: 'resource-summary', weight: 0, group: 'diagnostics'},
457
- {id: 'third-party-summary', weight: 0, group: 'diagnostics'},
458
- {id: 'third-party-facades', weight: 0, group: 'diagnostics'},
459
- {id: 'largest-contentful-paint-element', weight: 0, group: 'diagnostics'},
460
- {id: 'lcp-lazy-loaded', weight: 0, group: 'diagnostics'},
461
- {id: 'layout-shift-elements', weight: 0, group: 'diagnostics'},
462
- {id: 'uses-passive-event-listeners', weight: 0, group: 'diagnostics'},
463
- {id: 'no-document-write', weight: 0, group: 'diagnostics'},
464
- {id: 'long-tasks', weight: 0, group: 'diagnostics'},
465
- {id: 'non-composited-animations', weight: 0, group: 'diagnostics'},
466
- {id: 'unsized-images', weight: 0, group: 'diagnostics'},
467
- {id: 'viewport', weight: 0, group: 'diagnostics'},
468
- // Audits past this point don't belong to a group and will not be shown automatically
469
- {id: 'network-requests', weight: 0},
470
- {id: 'network-rtt', weight: 0},
471
- {id: 'network-server-latency', weight: 0},
472
- {id: 'main-thread-tasks', weight: 0},
473
- {id: 'diagnostics', weight: 0},
474
- {id: 'metrics', weight: 0},
475
- {id: 'screenshot-thumbnails', weight: 0},
476
- {id: 'final-screenshot', weight: 0},
477
- {id: 'script-treemap-data', weight: 0},
471
+
472
+ // Audits past this point contain useful data but are not displayed with other audits.
473
+ {id: 'network-requests', weight: 0, group: 'hidden'},
474
+ {id: 'network-rtt', weight: 0, group: 'hidden'},
475
+ {id: 'network-server-latency', weight: 0, group: 'hidden'},
476
+ {id: 'main-thread-tasks', weight: 0, group: 'hidden'},
477
+ {id: 'diagnostics', weight: 0, group: 'hidden'},
478
+ {id: 'metrics', weight: 0, group: 'hidden'},
479
+ {id: 'screenshot-thumbnails', weight: 0, group: 'hidden'},
480
+ {id: 'final-screenshot', weight: 0, group: 'hidden'},
481
+ {id: 'script-treemap-data', weight: 0, group: 'hidden'},
478
482
  ],
479
483
  },
480
484
  'accessibility': {
@@ -565,7 +569,6 @@ const defaultConfig = {
565
569
  {id: 'charset', weight: 1, group: 'best-practices-browser-compat'},
566
570
  // General Group
567
571
  {id: 'no-unload-listeners', weight: 1, group: 'best-practices-general'},
568
- {id: 'appcache-manifest', weight: 1, group: 'best-practices-general'},
569
572
  {id: 'js-libraries', weight: 0, group: 'best-practices-general'},
570
573
  {id: 'deprecations', weight: 1, group: 'best-practices-general'},
571
574
  {id: 'errors-in-console', weight: 1, group: 'best-practices-general'},
@@ -15,7 +15,7 @@ const frAudits = [
15
15
  /** @type {Record<string, LH.Config.AuditRefJson[]>} */
16
16
  const frCategoryAuditRefExtensions = {
17
17
  'performance': [
18
- {id: 'uses-responsive-images-snapshot', weight: 0, group: 'diagnostics'},
18
+ {id: 'uses-responsive-images-snapshot', weight: 0},
19
19
  ],
20
20
  };
21
21
 
@@ -37,7 +37,6 @@ const artifacts = {
37
37
  Trace: '',
38
38
  Accessibility: '',
39
39
  AnchorElements: '',
40
- AppCacheManifest: '',
41
40
  CacheContents: '',
42
41
  ConsoleMessages: '',
43
42
  CSSUsage: '',
@@ -88,7 +87,6 @@ const defaultConfig = {
88
87
  /* eslint-disable max-len */
89
88
  {id: artifacts.Accessibility, gatherer: 'accessibility'},
90
89
  {id: artifacts.AnchorElements, gatherer: 'anchor-elements'},
91
- {id: artifacts.AppCacheManifest, gatherer: 'dobetterweb/appcache'},
92
90
  {id: artifacts.CacheContents, gatherer: 'cache-contents'},
93
91
  {id: artifacts.ConsoleMessages, gatherer: 'console-messages'},
94
92
  {id: artifacts.CSSUsage, gatherer: 'css-usage'},
@@ -141,7 +139,6 @@ const defaultConfig = {
141
139
 
142
140
  artifacts.Accessibility,
143
141
  artifacts.AnchorElements,
144
- artifacts.AppCacheManifest,
145
142
  artifacts.CacheContents,
146
143
  artifacts.ConsoleMessages,
147
144
  artifacts.CSSUsage,
@@ -62,8 +62,13 @@ class FRGatherer {
62
62
  * @return {keyof LH.GathererArtifacts}
63
63
  */
64
64
  get name() {
65
+ let name = this.constructor.name;
66
+ // Rollup will mangle class names in an known way–just trim until `$`.
67
+ if (name.includes('$')) {
68
+ name = name.substr(0, name.indexOf('$'));
69
+ }
65
70
  // @ts-expect-error - assume that class name has been added to LH.GathererArtifacts.
66
- return this.constructor.name;
71
+ return name;
67
72
  }
68
73
 
69
74
  /**
@@ -43,7 +43,6 @@ async function clearDataForOrigin(session, url) {
43
43
  // indexeddb, websql, and localstorage are not cleared to prevent loss of potentially important data.
44
44
  // https://chromedevtools.github.io/debugger-protocol-viewer/tot/Storage/#type-StorageType
45
45
  const typesToClear = [
46
- 'appcache',
47
46
  // 'cookies',
48
47
  'file_systems',
49
48
  'shader_cache',
@@ -10,6 +10,7 @@
10
10
  */
11
11
  'use strict';
12
12
 
13
+ const {Buffer} = require('buffer');
13
14
  const FRGatherer = require('../../../fraggle-rock/gather/base-gatherer.js');
14
15
  const URL = require('../../../lib/url-shim.js');
15
16
  const Sentry = require('../../../lib/sentry.js');
@@ -12,7 +12,6 @@
12
12
  const log = require('lighthouse-logger');
13
13
  const FRGatherer = require('../../fraggle-rock/gather/base-gatherer.js');
14
14
  const pageFunctions = require('../../lib/page-functions.js');
15
- const URL = require('../../lib/url-shim.js');
16
15
  const FontSize = require('./seo/font-size.js');
17
16
 
18
17
  /* global window, getElementsInDocument, Image, getNodeDetails, ShadowRoot */
@@ -310,8 +309,6 @@ class ImageElements extends FRGatherer {
310
309
  let skippedCount = 0;
311
310
 
312
311
  for (const element of elements) {
313
- element.mimeType = URL.guessMimeType(element.src);
314
-
315
312
  if (reachedGatheringBudget) {
316
313
  skippedCount++;
317
314
  continue;
@@ -16,7 +16,10 @@ const Metrics = require('./traces/pwmetrics-events.js');
16
16
  const NetworkAnalysisComputed = require('../computed/network-analysis.js');
17
17
  const LoadSimulatorComputed = require('../computed/load-simulator.js');
18
18
  const LHError = require('../lib/lh-error.js');
19
- const pipeline = promisify(stream.pipeline);
19
+ // TODO(esmodules): Rollup does not support `promisfy` or `stream.pipeline`. Bundled files
20
+ // don't need anything in this file except for `stringifyReplacer`, so a check for
21
+ // truthiness before using is enough.
22
+ const pipeline = promisify && promisify(stream.pipeline);
20
23
 
21
24
  const artifactsFilename = 'artifacts.json';
22
25
  const traceSuffix = '.trace.json';
@@ -5,6 +5,8 @@
5
5
  */
6
6
  'use strict';
7
7
 
8
+ const process = require('process');
9
+
8
10
  module.exports = {
9
11
  // NODE_ENV is set to test by jest and by smokehouse CLI runner
10
12
  // CI as a catchall for everything we do in GitHub Actions
@@ -5,14 +5,7 @@
5
5
  */
6
6
  'use strict';
7
7
 
8
- const {
9
- filterOutRectsContainedByOthers,
10
- filterOutTinyRects,
11
- rectsTouchOrOverlap,
12
- rectContainsPoint,
13
- getBoundingRect,
14
- getRectCenterPoint,
15
- } = require('./rect-helpers.js');
8
+ const RectHelpers = require('./rect-helpers.js');
16
9
 
17
10
  /**
18
11
  * Merge client rects together and remove small ones. This may result in a larger overall
@@ -23,8 +16,8 @@ const {
23
16
  function getTappableRectsFromClientRects(clientRects) {
24
17
  // 1x1px rect shouldn't be reason to treat the rect as something the user should tap on.
25
18
  // Often they're made invisble in some obscure way anyway, and only exist for e.g. accessibiliity.
26
- clientRects = filterOutTinyRects(clientRects);
27
- clientRects = filterOutRectsContainedByOthers(clientRects);
19
+ clientRects = RectHelpers.filterOutTinyRects(clientRects);
20
+ clientRects = RectHelpers.filterOutRectsContainedByOthers(clientRects);
28
21
  clientRects = mergeTouchingClientRects(clientRects);
29
22
  return clientRects;
30
23
  }
@@ -68,17 +61,17 @@ function mergeTouchingClientRects(clientRects) {
68
61
  const rectsLineUpVertically =
69
62
  almostEqual(crA.left, crB.left) || almostEqual(crA.right, crB.right);
70
63
  const canMerge =
71
- rectsTouchOrOverlap(crA, crB) &&
64
+ RectHelpers.rectsTouchOrOverlap(crA, crB) &&
72
65
  (rectsLineUpHorizontally || rectsLineUpVertically);
73
66
 
74
67
  if (canMerge) {
75
- const replacementClientRect = getBoundingRect([crA, crB]);
76
- const mergedRectCenter = getRectCenterPoint(replacementClientRect);
68
+ const replacementClientRect = RectHelpers.getBoundingRect([crA, crB]);
69
+ const mergedRectCenter = RectHelpers.getRectCenterPoint(replacementClientRect);
77
70
 
78
71
  if (
79
72
  !(
80
- rectContainsPoint(crA, mergedRectCenter) ||
81
- rectContainsPoint(crB, mergedRectCenter)
73
+ RectHelpers.rectContainsPoint(crA, mergedRectCenter) ||
74
+ RectHelpers.rectContainsPoint(crB, mergedRectCenter)
82
75
  )
83
76
  ) {
84
77
  // Don't merge because the new shape is too different from the
@@ -20,6 +20,7 @@ const URL = require('./lib/url-shim.js');
20
20
  const Sentry = require('./lib/sentry.js');
21
21
  const generateReport = require('../report/generator/report-generator.js').generateReport;
22
22
  const LHError = require('./lib/lh-error.js');
23
+ const {version: lighthouseVersion} = require('../package.json');
23
24
 
24
25
  /** @typedef {import('./gather/connections/connection.js')} Connection */
25
26
  /** @typedef {import('./lib/arbitrary-equality-map.js')} ArbitraryEqualityMap */
@@ -112,7 +113,6 @@ class Runner {
112
113
  }
113
114
 
114
115
  // Entering: conclusion of the lighthouse result object
115
- const lighthouseVersion = require('../package.json').version;
116
116
 
117
117
  // Use version from gathering stage.
118
118
  // If accessibility gatherer didn't run or errored, it won't be in credits.
@@ -519,10 +519,9 @@ class Util {
519
519
  let totalWeight = 0;
520
520
  for (const auditRef of category.auditRefs) {
521
521
  const auditPassed = Util.showAsPassed(auditRef.result);
522
- const notDisplayed = !auditRef.group && category.id === 'performance';
523
522
 
524
523
  // Don't count the audit if it's manual, N/A, or isn't displayed.
525
- if (notDisplayed ||
524
+ if (auditRef.group === 'hidden' ||
526
525
  auditRef.result.scoreDisplayMode === 'manual' ||
527
526
  auditRef.result.scoreDisplayMode === 'notApplicable') {
528
527
  continue;