lighthouse 9.1.0-dev.20211213 → 9.2.0

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 (44) hide show
  1. package/changelog.md +50 -3
  2. package/lighthouse-core/audits/apple-touch-icon.js +2 -2
  3. package/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js +1 -14
  4. package/lighthouse-core/audits/byte-efficiency/legacy-javascript.js +0 -3
  5. package/lighthouse-core/audits/no-unload-listeners.js +1 -1
  6. package/lighthouse-core/computed/critical-request-chains.js +2 -2
  7. package/lighthouse-core/computed/load-simulator.js +1 -0
  8. package/lighthouse-core/computed/unused-css.js +3 -3
  9. package/lighthouse-core/config/default-config.js +1 -1
  10. package/lighthouse-core/fraggle-rock/gather/base-gatherer.js +1 -1
  11. package/lighthouse-core/gather/driver/wait-for-condition.js +1 -1
  12. package/lighthouse-core/gather/gatherers/accessibility.js +1 -1
  13. package/lighthouse-core/gather/gatherers/anchor-elements.js +1 -1
  14. package/lighthouse-core/gather/gatherers/cache-contents.js +1 -1
  15. package/lighthouse-core/gather/gatherers/console-messages.js +1 -1
  16. package/lighthouse-core/gather/gatherers/dobetterweb/doctype.js +1 -1
  17. package/lighthouse-core/gather/gatherers/dobetterweb/domstats.js +1 -1
  18. package/lighthouse-core/gather/gatherers/dobetterweb/optimized-images.js +1 -1
  19. package/lighthouse-core/gather/gatherers/dobetterweb/password-inputs-with-prevented-paste.js +1 -1
  20. package/lighthouse-core/gather/gatherers/dobetterweb/response-compression.js +1 -1
  21. package/lighthouse-core/gather/gatherers/dobetterweb/tags-blocking-first-paint.js +2 -2
  22. package/lighthouse-core/gather/gatherers/form-elements.js +3 -3
  23. package/lighthouse-core/gather/gatherers/full-page-screenshot.js +1 -1
  24. package/lighthouse-core/gather/gatherers/global-listeners.js +1 -1
  25. package/lighthouse-core/gather/gatherers/iframe-elements.js +1 -1
  26. package/lighthouse-core/gather/gatherers/inspector-issues.js +1 -1
  27. package/lighthouse-core/gather/gatherers/js-usage.js +1 -1
  28. package/lighthouse-core/gather/gatherers/main-document-content.js +1 -1
  29. package/lighthouse-core/gather/gatherers/meta-elements.js +1 -1
  30. package/lighthouse-core/gather/gatherers/script-elements.js +1 -1
  31. package/lighthouse-core/gather/gatherers/seo/embedded-content.js +1 -1
  32. package/lighthouse-core/gather/gatherers/seo/font-size.js +8 -5
  33. package/lighthouse-core/gather/gatherers/seo/robots-txt.js +1 -1
  34. package/lighthouse-core/gather/gatherers/service-worker.js +1 -1
  35. package/lighthouse-core/gather/gatherers/source-maps.js +1 -1
  36. package/lighthouse-core/gather/gatherers/trace-elements.js +1 -1
  37. package/lighthouse-core/gather/gatherers/viewport-dimensions.js +1 -1
  38. package/lighthouse-core/lib/dependency-graph/simulator/network-analyzer.js +3 -2
  39. package/lighthouse-core/lib/dependency-graph/simulator/simulator.js +17 -0
  40. package/package.json +9 -8
  41. package/shared/localization/locales/en-US.json +1 -1
  42. package/shared/localization/locales/en-XL.json +1 -1
  43. package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +1 -0
  44. package/types/gatherer.d.ts +1 -0
package/changelog.md CHANGED
@@ -1,3 +1,50 @@
1
+ <a name="9.2.0"></a>
2
+ # 9.2.0 (2021-12-15)
3
+ [Full Changelog](https://github.com/GoogleChrome/lighthouse/compare/v9.1.0...v9.2.0)
4
+
5
+ We expect this release to ship in the DevTools of [Chrome 99](https://chromiumdash.appspot.com/schedule), and to PageSpeed Insights within 2 weeks.
6
+
7
+ ## Notable Changes
8
+
9
+ * move no-unload-listeners to perf category ([#13497](https://github.com/GoogleChrome/lighthouse/pull/13497))
10
+
11
+ ## Core
12
+
13
+ * font-size: fix CSS selector regex ([#13455](https://github.com/GoogleChrome/lighthouse/pull/13455))
14
+ * fcp: handle negative request `endTime` ([#13452](https://github.com/GoogleChrome/lighthouse/pull/13452))
15
+ * legacy-javascript: update polyfilling, drop some signals ([#13482](https://github.com/GoogleChrome/lighthouse/pull/13482), [#13442](https://github.com/GoogleChrome/lighthouse/pull/13442))
16
+ * cache fetch to avoid bad polyfills ([#13476](https://github.com/GoogleChrome/lighthouse/pull/13476))
17
+ * check equality of computed artifacts using dependency keys ([#13430](https://github.com/GoogleChrome/lighthouse/pull/13430))
18
+
19
+ ## ⛏️👷 Fraggle Rock
20
+
21
+ Support for auditing user flows ([#11313](https://github.com/GoogleChrome/lighthouse/issues/11313))
22
+
23
+ * compute timespan saving with observed throughput ([#13478](https://github.com/GoogleChrome/lighthouse/pull/13478))
24
+ * option to skip about:blank jumps ([#13375](https://github.com/GoogleChrome/lighthouse/pull/13375))
25
+
26
+ ## Report
27
+
28
+ * psi: update styles for tighter fit in narrow viewports ([#13355](https://github.com/GoogleChrome/lighthouse/pull/13355))
29
+
30
+ ## Deps
31
+
32
+ * bump eslint and related items ([#13484](https://github.com/GoogleChrome/lighthouse/pull/13484))
33
+ * axe-core: upgrade to 4.3.5 ([#13441](https://github.com/GoogleChrome/lighthouse/pull/13441))
34
+
35
+ ## Tests
36
+
37
+ * smoke: fix chromestatus url ([#13475](https://github.com/GoogleChrome/lighthouse/pull/13475))
38
+ * split smoke tests into one test per file ([#13461](https://github.com/GoogleChrome/lighthouse/pull/13461))
39
+ * fix devtools build command ([#13457](https://github.com/GoogleChrome/lighthouse/pull/13457))
40
+ * move sharding higher so smokehouse-bundle can also shard ([#13387](https://github.com/GoogleChrome/lighthouse/pull/13387))
41
+ * port axe test to pptr ([#13450](https://github.com/GoogleChrome/lighthouse/pull/13450))
42
+
43
+ ## Misc
44
+
45
+ * build: build test flow report to same path as sample-reports ([#13324](https://github.com/GoogleChrome/lighthouse/pull/13324))
46
+ * treemap: add `lang` to html tag ([#13454](https://github.com/GoogleChrome/lighthouse/pull/13454))
47
+
1
48
  <a name="9.1.0"></a>
2
49
  # 9.1.0 (2021-11-24)
3
50
  [Full Changelog](https://github.com/GoogleChrome/lighthouse/compare/v9.0.0...v9.1.0)
@@ -6,7 +53,7 @@ We expect this release to ship in the DevTools of [Chrome 98](https://chromiumda
6
53
 
7
54
  ## New Contributors
8
55
 
9
- Thanks to our new contributors 👽🐷🐰🐯🐻!
56
+ Thanks to our new contributors 👽🐷🐰🐯🐻!
10
57
 
11
58
  - @whitep4nth3r
12
59
  - Adam Read @adamread
@@ -78,7 +125,7 @@ See the [What's new in Lighthouse 9.0 blog post](https://developer.chrome.com/bl
78
125
 
79
126
  ## New Contributors
80
127
 
81
- Thanks to our new contributors 👽🐷🐰🐯🐻!
128
+ Thanks to our new contributors 👽🐷🐰🐯🐻!
82
129
 
83
130
  - Sergii Bondarenko @BR0kEN-
84
131
  - Prerana Nawar @prerana1821
@@ -197,7 +244,7 @@ We expect this release to ship in the DevTools of [Chrome 97](https://chromiumda
197
244
 
198
245
  ## New Contributors
199
246
 
200
- Thanks to our new contributors 👽🐷🐰🐯🐻!
247
+ Thanks to our new contributors 👽🐷🐰🐯🐻!
201
248
 
202
249
  - meehawk @meehawk
203
250
  - Edwin Gustafson @edwingustafson
@@ -56,8 +56,8 @@ class AppleTouchIcon extends Audit {
56
56
  const passed = appleTouchIcons.length !== 0;
57
57
 
58
58
  const warnings = [];
59
- if (appleTouchIcons.filter(el => el.rel === 'apple-touch-icon-precomposed').length !== 0
60
- && appleTouchIcons.filter(el => el.rel === 'apple-touch-icon').length === 0) {
59
+ if (appleTouchIcons.filter(el => el.rel === 'apple-touch-icon-precomposed').length !== 0 &&
60
+ appleTouchIcons.filter(el => el.rel === 'apple-touch-icon').length === 0) {
61
61
  warnings.push(str_(UIStrings.precomposedWarning));
62
62
  }
63
63
 
@@ -200,19 +200,6 @@ class UnusedBytes extends Audit {
200
200
  return Math.round(Math.max(savings, 0) / 10) * 10;
201
201
  }
202
202
 
203
- /**
204
- * @param {number} wastedBytes
205
- * @param {Simulator} simulator
206
- */
207
- static computeWastedMsWithThroughput(wastedBytes, simulator) {
208
- const bitsPerSecond = simulator.getOptions().throughput;
209
- // https://github.com/GoogleChrome/lighthouse/pull/13323#issuecomment-962031709
210
- if (bitsPerSecond === 0) return 0;
211
- const wastedBits = wastedBytes * 8;
212
- const wastedMs = wastedBits / bitsPerSecond * 1000;
213
- return wastedMs;
214
- }
215
-
216
203
  /**
217
204
  * @param {ByteEfficiencyProduct} result
218
205
  * @param {Node|null} graph
@@ -232,7 +219,7 @@ class UnusedBytes extends Audit {
232
219
  providedWastedBytesByUrl: result.wastedBytesByUrl,
233
220
  });
234
221
  } else {
235
- wastedMs = this.computeWastedMsWithThroughput(wastedBytes, simulator);
222
+ wastedMs = simulator.computeWastedMsFromWastedBytes(wastedBytes);
236
223
  }
237
224
 
238
225
  let displayValue = result.displayValue || '';
@@ -178,8 +178,6 @@ class LegacyJavascript extends ByteEfficiencyAudit {
178
178
  ['Array.isArray', 'es6.array.is-array'],
179
179
  ['Array.prototype.map', 'es6.array.map'],
180
180
  ['Array.of', 'es6.array.of'],
181
- ['Array.prototype.reduce', 'es6.array.reduce'],
182
- ['Array.prototype.reduceRight', 'es6.array.reduce-right'],
183
181
  ['Array.prototype.some', 'es6.array.some'],
184
182
  ['Date.now', 'es6.date.now'],
185
183
  ['Date.prototype.toISOString', 'es6.date.to-iso-string'],
@@ -188,7 +186,6 @@ class LegacyJavascript extends ByteEfficiencyAudit {
188
186
  ['Function.prototype.name', 'es6.function.name'],
189
187
  ['Number.isInteger', 'es6.number.is-integer'],
190
188
  ['Number.isSafeInteger', 'es6.number.is-safe-integer'],
191
- ['Number.parseInt', 'es6.number.parse-int'],
192
189
  ['Object.defineProperties', 'es6.object.define-properties'],
193
190
  ['Object.defineProperty', 'es6.object.define-property'],
194
191
  ['Object.freeze', 'es6.object.freeze'],
@@ -15,7 +15,7 @@ const UIStrings = {
15
15
  /** Descriptive title of a Lighthouse audit that checks if a web page has 'unload' event listeners and finds that it is using them. */
16
16
  failureTitle: 'Registers an `unload` listener',
17
17
  /** Description of a Lighthouse audit that tells the user why pages should not use the 'unload' event. This is displayed after a user expands the section to see more. 'Learn More' becomes link text to additional documentation. */
18
- description: 'The `unload` event does not fire reliably and listening for it can prevent browser optimizations like the Back-Forward Cache. Consider using the `pagehide` or `visibilitychange` events instead. [Learn more](https://developers.google.com/web/updates/2018/07/page-lifecycle-api#the-unload-event)',
18
+ description: 'The `unload` event does not fire reliably and listening for it can prevent browser optimizations like the Back-Forward Cache. Use `pagehide` or `visibilitychange` events instead. [Learn more](https://web.dev/bfcache/#never-use-the-unload-event)',
19
19
  };
20
20
 
21
21
  const str_ = i18n.createMessageInstanceIdFn(__filename, UIStrings);
@@ -41,8 +41,8 @@ class CriticalRequestChains {
41
41
  }
42
42
 
43
43
  // Iframes are considered High Priority but they are not render blocking
44
- const isIframe = request.resourceType === NetworkRequest.TYPES.Document
45
- && request.frameId !== mainResource.frameId;
44
+ const isIframe = request.resourceType === NetworkRequest.TYPES.Document &&
45
+ request.frameId !== mainResource.frameId;
46
46
  // XHRs are fetched at High priority, but we exclude them, as they are unlikely to be critical
47
47
  // Images are also non-critical.
48
48
  // Treat any missed images, primarily favicons, as non-critical resources
@@ -24,6 +24,7 @@ class LoadSimulator {
24
24
  const options = {
25
25
  additionalRttByOrigin: networkAnalysis.additionalRttByOrigin,
26
26
  serverResponseTimeByOrigin: networkAnalysis.serverResponseTimeByOrigin,
27
+ observedThroughput: networkAnalysis.throughput,
27
28
  };
28
29
 
29
30
  // If we have precomputed lantern data, overwrite our observed estimates and use precomputed instead
@@ -98,9 +98,9 @@ class UnusedCSS {
98
98
  const firstRuleStart = preview.indexOf('{');
99
99
  const firstRuleEnd = preview.indexOf('}');
100
100
 
101
- if (firstRuleStart === -1 || firstRuleEnd === -1
102
- || firstRuleStart > firstRuleEnd
103
- || firstRuleStart > PREVIEW_LENGTH) {
101
+ if (firstRuleStart === -1 || firstRuleEnd === -1 ||
102
+ firstRuleStart > firstRuleEnd ||
103
+ firstRuleStart > PREVIEW_LENGTH) {
104
104
  // We couldn't determine the first rule-set or it's not within the preview
105
105
  preview = preview.slice(0, PREVIEW_LENGTH) + '...';
106
106
  } else if (firstRuleEnd < PREVIEW_LENGTH) {
@@ -463,6 +463,7 @@ const defaultConfig = {
463
463
  {id: 'non-composited-animations', weight: 0},
464
464
  {id: 'unsized-images', weight: 0},
465
465
  {id: 'viewport', weight: 0},
466
+ {id: 'no-unload-listeners', weight: 0},
466
467
 
467
468
  // Budget audits.
468
469
  {id: 'performance-budget', weight: 0, group: 'budgets'},
@@ -566,7 +567,6 @@ const defaultConfig = {
566
567
  {id: 'doctype', weight: 1, group: 'best-practices-browser-compat'},
567
568
  {id: 'charset', weight: 1, group: 'best-practices-browser-compat'},
568
569
  // General Group
569
- {id: 'no-unload-listeners', weight: 1, group: 'best-practices-general'},
570
570
  {id: 'js-libraries', weight: 0, group: 'best-practices-general'},
571
571
  {id: 'deprecations', weight: 1, group: 'best-practices-general'},
572
572
  {id: 'errors-in-console', weight: 1, group: 'best-practices-general'},
@@ -17,7 +17,7 @@
17
17
  */
18
18
  class FRGatherer {
19
19
  /** @type {LH.Gatherer.GathererMeta} */
20
- meta = {supportedModes: []}
20
+ meta = {supportedModes: []};
21
21
 
22
22
  /**
23
23
  * Method to start observing a page for an arbitrary period of time.
@@ -5,7 +5,7 @@
5
5
  */
6
6
  'use strict';
7
7
 
8
- /* global window, performance */
8
+ /* global window */
9
9
 
10
10
  const log = require('lighthouse-logger');
11
11
  const LHError = require('../../lib/lh-error.js');
@@ -148,7 +148,7 @@ class Accessibility extends FRGatherer {
148
148
  /** @type {LH.Gatherer.GathererMeta} */
149
149
  meta = {
150
150
  supportedModes: ['snapshot', 'navigation'],
151
- }
151
+ };
152
152
 
153
153
  /**
154
154
  * @param {LH.Gatherer.FRTransitionalContext} passContext
@@ -94,7 +94,7 @@ class AnchorElements extends FRGatherer {
94
94
  /** @type {LH.Gatherer.GathererMeta} */
95
95
  meta = {
96
96
  supportedModes: ['snapshot', 'navigation'],
97
- }
97
+ };
98
98
 
99
99
  /**
100
100
  * @param {LH.Gatherer.FRTransitionalContext} passContext
@@ -41,7 +41,7 @@ class CacheContents extends FRGatherer {
41
41
  /** @type {LH.Gatherer.GathererMeta} */
42
42
  meta = {
43
43
  supportedModes: ['snapshot', 'navigation'],
44
- }
44
+ };
45
45
 
46
46
  /**
47
47
  * Creates an array of cached URLs.
@@ -34,7 +34,7 @@ class ConsoleMessages extends FRGatherer {
34
34
  /** @type {LH.Gatherer.GathererMeta} */
35
35
  meta = {
36
36
  supportedModes: ['timespan', 'navigation'],
37
- }
37
+ };
38
38
 
39
39
  constructor() {
40
40
  super();
@@ -28,7 +28,7 @@ class Doctype extends FRGatherer {
28
28
  /** @type {LH.Gatherer.GathererMeta} */
29
29
  meta = {
30
30
  supportedModes: ['snapshot', 'navigation'],
31
- }
31
+ };
32
32
 
33
33
  /**
34
34
  * @param {LH.Gatherer.FRTransitionalContext} passContext
@@ -80,7 +80,7 @@ class DOMStats extends FRGatherer {
80
80
  /** @type {LH.Gatherer.GathererMeta} */
81
81
  meta = {
82
82
  supportedModes: ['snapshot', 'navigation'],
83
- }
83
+ };
84
84
 
85
85
  /**
86
86
  * @param {LH.Gatherer.FRTransitionalContext} passContext
@@ -38,7 +38,7 @@ class OptimizedImages extends FRGatherer {
38
38
  meta = {
39
39
  supportedModes: ['timespan', 'navigation'],
40
40
  dependencies: {DevtoolsLog: DevtoolsLog.symbol},
41
- }
41
+ };
42
42
 
43
43
  constructor() {
44
44
  super();
@@ -32,7 +32,7 @@ class PasswordInputsWithPreventedPaste extends FRGatherer {
32
32
  /** @type {LH.Gatherer.GathererMeta} */
33
33
  meta = {
34
34
  supportedModes: ['snapshot', 'navigation'],
35
- }
35
+ };
36
36
 
37
37
  /**
38
38
  * @param {LH.Gatherer.FRTransitionalContext} passContext
@@ -43,7 +43,7 @@ class ResponseCompression extends FRGatherer {
43
43
  meta = {
44
44
  supportedModes: ['timespan', 'navigation'],
45
45
  dependencies: {DevtoolsLog: DevtoolsLog.symbol},
46
- }
46
+ };
47
47
 
48
48
  /**
49
49
  * @param {LH.Artifacts.NetworkRequest[]} networkRecords
@@ -22,7 +22,7 @@ const NetworkRecords = require('../../../computed/network-records.js');
22
22
  const DevtoolsLog = require('../devtools-log.js');
23
23
  const FRGatherer = require('../../../fraggle-rock/gather/base-gatherer.js');
24
24
 
25
- /* global document, window, performance, HTMLLinkElement, SVGScriptElement */
25
+ /* global document, window, HTMLLinkElement, SVGScriptElement */
26
26
 
27
27
  /** @typedef {{href: string, media: string, msSinceHTMLEnd: number, matches: boolean}} MediaChange */
28
28
  /** @typedef {{tagName: 'LINK', url: string, href: string, rel: string, media: string, disabled: boolean, mediaChanges: Array<MediaChange>}} LinkTag */
@@ -119,7 +119,7 @@ class TagsBlockingFirstPaint extends FRGatherer {
119
119
  meta = {
120
120
  supportedModes: ['navigation'],
121
121
  dependencies: {DevtoolsLog: DevtoolsLog.symbol},
122
- }
122
+ };
123
123
 
124
124
  /**
125
125
  * @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
@@ -49,8 +49,8 @@ function collectFormElements() {
49
49
  forms.set(parentFormElement, newFormObj);
50
50
  }
51
51
  const formObj = forms.get(parentFormElement) || formlessObj;
52
- if (child instanceof HTMLInputElement || child instanceof HTMLTextAreaElement
53
- || child instanceof HTMLSelectElement) {
52
+ if (child instanceof HTMLInputElement || child instanceof HTMLTextAreaElement ||
53
+ child instanceof HTMLSelectElement) {
54
54
  formObj.inputs.push({
55
55
  id: child.id,
56
56
  name: child.name,
@@ -89,7 +89,7 @@ class FormElements extends FRGatherer {
89
89
  /** @type {LH.Gatherer.GathererMeta} */
90
90
  meta = {
91
91
  supportedModes: ['snapshot', 'navigation'],
92
- }
92
+ };
93
93
 
94
94
  /**
95
95
  * @param {LH.Gatherer.FRTransitionalContext} passContext
@@ -46,7 +46,7 @@ class FullPageScreenshot extends FRGatherer {
46
46
  /** @type {LH.Gatherer.GathererMeta} */
47
47
  meta = {
48
48
  supportedModes: ['snapshot', 'timespan', 'navigation'],
49
- }
49
+ };
50
50
 
51
51
  /**
52
52
  * @param {LH.Gatherer.FRTransitionalContext} context
@@ -18,7 +18,7 @@ class GlobalListeners extends FRGatherer {
18
18
  /** @type {LH.Gatherer.GathererMeta} */
19
19
  meta = {
20
20
  supportedModes: ['snapshot', 'timespan', 'navigation'],
21
- }
21
+ };
22
22
 
23
23
  /**
24
24
  * @param {LH.Crdp.DOMDebugger.EventListener} listener
@@ -39,7 +39,7 @@ class IFrameElements extends FRGatherer {
39
39
  /** @type {LH.Gatherer.GathererMeta} */
40
40
  meta = {
41
41
  supportedModes: ['snapshot', 'navigation'],
42
- }
42
+ };
43
43
 
44
44
  /**
45
45
  * @param {LH.Gatherer.FRTransitionalContext} passContext
@@ -19,7 +19,7 @@ class InspectorIssues extends FRGatherer {
19
19
  meta = {
20
20
  supportedModes: ['timespan', 'navigation'],
21
21
  dependencies: {DevtoolsLog: DevtoolsLog.symbol},
22
- }
22
+ };
23
23
 
24
24
  constructor() {
25
25
  super();
@@ -14,7 +14,7 @@ class JsUsage extends FRGatherer {
14
14
  /** @type {LH.Gatherer.GathererMeta} */
15
15
  meta = {
16
16
  supportedModes: ['snapshot', 'timespan', 'navigation'],
17
- }
17
+ };
18
18
 
19
19
  constructor() {
20
20
  super();
@@ -19,7 +19,7 @@ class MainDocumentContent extends FRGatherer {
19
19
  meta = {
20
20
  supportedModes: ['navigation'],
21
21
  dependencies: {DevtoolsLog: DevtoolsLog.symbol},
22
- }
22
+ };
23
23
 
24
24
  /**
25
25
  *
@@ -43,7 +43,7 @@ class MetaElements extends FRGatherer {
43
43
  /** @type {LH.Gatherer.GathererMeta} */
44
44
  meta = {
45
45
  supportedModes: ['snapshot', 'navigation'],
46
- }
46
+ };
47
47
 
48
48
  /**
49
49
  * @param {LH.Gatherer.FRTransitionalContext} passContext
@@ -70,7 +70,7 @@ class ScriptElements extends FRGatherer {
70
70
  meta = {
71
71
  supportedModes: ['timespan', 'navigation'],
72
72
  dependencies: {DevtoolsLog: DevtoolsLog.symbol},
73
- }
73
+ };
74
74
 
75
75
  /**
76
76
  * @param {LH.Gatherer.FRTransitionalContext} context
@@ -44,7 +44,7 @@ class EmbeddedContent extends FRGatherer {
44
44
  /** @type {LH.Gatherer.GathererMeta} */
45
45
  meta = {
46
46
  supportedModes: ['snapshot', 'navigation'],
47
- }
47
+ };
48
48
 
49
49
  /**
50
50
  * @param {LH.Gatherer.FRTransitionalContext} passContext
@@ -36,25 +36,28 @@ function hasFontSizeDeclaration(style) {
36
36
 
37
37
  /**
38
38
  * Computes the CSS specificity of a given selector, i.e. #id > .class > div
39
+ * TODO: Handle pseudo selectors (:not(), :where, :nth-child) and attribute selectors
39
40
  * LIMITATION: !important is not respected
40
41
  *
41
42
  * @see https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
42
43
  * @see https://www.smashingmagazine.com/2010/04/css-specificity-and-inheritance/
44
+ * @see https://drafts.csswg.org/selectors-4/#specificity-rules
43
45
  *
44
46
  * @param {string} selector
45
47
  * @return {number}
46
48
  */
47
49
  function computeSelectorSpecificity(selector) {
48
- const tokens = selector.split(' ');
50
+ // Remove universal selector and separator characters, then split.
51
+ const tokens = selector.replace(/[*\s+>~]/g, ' ').split(' ');
49
52
 
50
53
  let numIDs = 0;
51
54
  let numClasses = 0;
52
55
  let numTypes = 0;
53
56
 
54
57
  for (const token of tokens) {
55
- const ids = token.match(/\b#[a-z0-9]+/g) || [];
56
- const classes = token.match(/\b\.[a-z0-9]+/g) || [];
57
- const types = token.match(/^[a-z]+/) ? [1] : [];
58
+ const ids = token.match(/(\b|^)#[a-z0-9_-]+/gi) || [];
59
+ const classes = token.match(/(\b|^)\.[a-z0-9_-]+/gi) || [];
60
+ const types = token.match(/^[a-z]+/i) ? [1] : [];
58
61
  numIDs += ids.length;
59
62
  numClasses += classes.length;
60
63
  numTypes += types.length;
@@ -182,7 +185,7 @@ class FontSize extends FRGatherer {
182
185
  /** @type {LH.Gatherer.GathererMeta} */
183
186
  meta = {
184
187
  supportedModes: ['snapshot', 'navigation'],
185
- }
188
+ };
186
189
 
187
190
  /**
188
191
  * @param {LH.Gatherer.FRProtocolSession} session
@@ -30,7 +30,7 @@ class RobotsTxt extends FRGatherer {
30
30
  /** @type {LH.Gatherer.GathererMeta} */
31
31
  meta = {
32
32
  supportedModes: ['snapshot', 'navigation'],
33
- }
33
+ };
34
34
 
35
35
  /**
36
36
  * @param {LH.Gatherer.FRTransitionalContext} passContext
@@ -12,7 +12,7 @@ class ServiceWorker extends FRGatherer {
12
12
  /** @type {LH.Gatherer.GathererMeta} */
13
13
  meta = {
14
14
  supportedModes: ['navigation'],
15
- }
15
+ };
16
16
 
17
17
  /**
18
18
  * @param {LH.Gatherer.PassContext} passContext
@@ -15,7 +15,7 @@ class SourceMaps extends FRGatherer {
15
15
  /** @type {LH.Gatherer.GathererMeta} */
16
16
  meta = {
17
17
  supportedModes: ['timespan', 'navigation'],
18
- }
18
+ };
19
19
 
20
20
  constructor() {
21
21
  super();
@@ -45,7 +45,7 @@ class TraceElements extends FRGatherer {
45
45
  meta = {
46
46
  supportedModes: ['timespan', 'navigation'],
47
47
  dependencies: {Trace: Trace.symbol},
48
- }
48
+ };
49
49
 
50
50
  /** @type {Map<string, string>} */
51
51
  animationIdToName = new Map();
@@ -31,7 +31,7 @@ class ViewportDimensions extends FRGatherer {
31
31
  /** @type {LH.Gatherer.GathererMeta} */
32
32
  meta = {
33
33
  supportedModes: ['snapshot', 'timespan', 'navigation'],
34
- }
34
+ };
35
35
 
36
36
  /**
37
37
  * @param {LH.Gatherer.FRTransitionalContext} passContext
@@ -198,8 +198,9 @@ class NetworkAnalyzer {
198
198
  if (!Number.isFinite(timing.receiveHeadersEnd) || timing.receiveHeadersEnd < 0) return;
199
199
  if (!record.resourceType) return;
200
200
 
201
- const serverResponseTimePercentage = SERVER_RESPONSE_PERCENTAGE_OF_TTFB[record.resourceType]
202
- || DEFAULT_SERVER_RESPONSE_PERCENTAGE;
201
+ const serverResponseTimePercentage =
202
+ SERVER_RESPONSE_PERCENTAGE_OF_TTFB[record.resourceType] ||
203
+ DEFAULT_SERVER_RESPONSE_PERCENTAGE;
203
204
  const estimatedServerResponseTime = timing.receiveHeadersEnd * serverResponseTimePercentage;
204
205
 
205
206
  // When connection was reused...
@@ -486,6 +486,23 @@ class Simulator {
486
486
  };
487
487
  }
488
488
 
489
+ /**
490
+ * @param {number} wastedBytes
491
+ */
492
+ computeWastedMsFromWastedBytes(wastedBytes) {
493
+ const {throughput, observedThroughput} = this._options;
494
+
495
+ // https://github.com/GoogleChrome/lighthouse/pull/13323#issuecomment-962031709
496
+ // 0 throughput means the no (additional) throttling is expected.
497
+ // This is common for desktop + devtools throttling where throttling is additive and we don't want any additional.
498
+ const bitsPerSecond = throughput === 0 ? observedThroughput : throughput;
499
+ if (bitsPerSecond === 0) return 0;
500
+
501
+ const wastedBits = wastedBytes * 8;
502
+ const wastedMs = wastedBits / bitsPerSecond * 1000;
503
+ return wastedMs;
504
+ }
505
+
489
506
  /** @return {Map<string, LH.Gatherer.Simulation.Result['nodeTimings']>} */
490
507
  static get ALL_NODE_TIMINGS() {
491
508
  return ALL_SIMULATION_NODE_TIMINGS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lighthouse",
3
- "version": "9.1.0-dev.20211213",
3
+ "version": "9.2.0",
4
4
  "description": "Automated auditing, performance metrics, and best practices for the web.",
5
5
  "main": "./lighthouse-core/index.js",
6
6
  "bin": {
@@ -111,7 +111,7 @@
111
111
  "@types/chrome": "^0.0.154",
112
112
  "@types/configstore": "^4.0.0",
113
113
  "@types/cpy": "^5.1.0",
114
- "@types/eslint": "^4.16.6",
114
+ "@types/eslint": "^8.2.1",
115
115
  "@types/estree": "^0.0.50",
116
116
  "@types/gh-pages": "^2.0.0",
117
117
  "@types/google.analytics": "0.0.39",
@@ -132,8 +132,8 @@
132
132
  "@types/ws": "^7.0.0",
133
133
  "@types/yargs": "^16.0.0",
134
134
  "@types/yargs-parser": "^15.0.0",
135
- "@typescript-eslint/eslint-plugin": "^4.30.0",
136
- "@typescript-eslint/parser": "^4.30.0",
135
+ "@typescript-eslint/eslint-plugin": "^5.6.0",
136
+ "@typescript-eslint/parser": "^5.6.0",
137
137
  "acorn": "^8.5.0",
138
138
  "angular": "^1.7.4",
139
139
  "archiver": "^3.0.0",
@@ -146,10 +146,11 @@
146
146
  "csv-validator": "^0.0.3",
147
147
  "devtools-protocol": "0.0.939404",
148
148
  "es-main": "^1.0.2",
149
- "eslint": "^7.23.0",
150
- "eslint-config-google": "^0.9.1",
151
- "eslint-plugin-import": "^2.24.2",
152
- "eslint-plugin-local-rules": "0.1.0",
149
+ "eslint": "^8.4.1",
150
+ "eslint-config-google": "^0.14.0",
151
+ "eslint-formatter-codeframe": "^7.32.1",
152
+ "eslint-plugin-import": "^2.25.3",
153
+ "eslint-plugin-local-rules": "1.1.0",
153
154
  "event-target-shim": "^6.0.2",
154
155
  "firebase": "^9.0.2",
155
156
  "gh-pages": "^2.0.1",
@@ -1218,7 +1218,7 @@
1218
1218
  "message": "Server Backend Latencies"
1219
1219
  },
1220
1220
  "lighthouse-core/audits/no-unload-listeners.js | description": {
1221
- "message": "The `unload` event does not fire reliably and listening for it can prevent browser optimizations like the Back-Forward Cache. Consider using the `pagehide` or `visibilitychange` events instead. [Learn more](https://developers.google.com/web/updates/2018/07/page-lifecycle-api#the-unload-event)"
1221
+ "message": "The `unload` event does not fire reliably and listening for it can prevent browser optimizations like the Back-Forward Cache. Use `pagehide` or `visibilitychange` events instead. [Learn more](https://web.dev/bfcache/#never-use-the-unload-event)"
1222
1222
  },
1223
1223
  "lighthouse-core/audits/no-unload-listeners.js | failureTitle": {
1224
1224
  "message": "Registers an `unload` listener"
@@ -1218,7 +1218,7 @@
1218
1218
  "message": "Ŝér̂v́êŕ B̂áĉḱêńd̂ Ĺât́êńĉíêś"
1219
1219
  },
1220
1220
  "lighthouse-core/audits/no-unload-listeners.js | description": {
1221
- "message": "T̂h́ê `unload` év̂én̂t́ d̂óêś n̂ót̂ f́îŕê ŕêĺîáb̂ĺŷ án̂d́ l̂íŝt́êńîńĝ f́ôŕ ît́ ĉán̂ ṕr̂év̂én̂t́ b̂ŕôẃŝér̂ óp̂t́îḿîźât́îón̂ś l̂ík̂é t̂h́ê B́âćk̂-F́ôŕŵár̂d́ Ĉáĉh́ê. Ćôńíd̂ úŝín̂ǵ t̂h́ê `pagehide` ó `visibilitychange` év̂én̂t́n̂śt̂éd́. [L̂éâŕôŕ](https://developers.google.com/web/updates/2018/07/page-lifecycle-api#the-unload-event)"
1221
+ "message": "T̂h́ê `unload` év̂én̂t́ d̂óêś n̂ót̂ f́îŕê ŕêĺîáb̂ĺŷ án̂d́ l̂íŝt́êńîńĝ f́ôŕ ît́ ĉán̂ ṕr̂év̂én̂t́ b̂ŕôẃŝér̂ óp̂t́îḿîźât́îón̂ś l̂ík̂é t̂h́ê B́âćk̂-F́ôŕŵár̂d́ Ĉáĉh́ê. Úŝé `pagehide` ôŕ `visibilitychange` êv́êńt̂ś îńŝt́êád̂. [Ĺêár̂ń m̂ór̂é](https://web.dev/bfcache/#never-use-the-unload-event)"
1222
1222
  },
1223
1223
  "lighthouse-core/audits/no-unload-listeners.js | failureTitle": {
1224
1224
  "message": "R̂éĝíŝt́êŕŝ án̂ `unload` ĺîśt̂én̂ér̂"
@@ -36,6 +36,7 @@ describe('issueAdded types', () => {
36
36
  Array [
37
37
  "attributionReportingIssueDetails",
38
38
  "blockedByResponseIssueDetails",
39
+ "clientHintIssueDetails",
39
40
  "contentSecurityPolicyIssueDetails",
40
41
  "corsIssueDetails",
41
42
  "deprecationIssueDetails",
@@ -153,6 +153,7 @@ declare module Gatherer {
153
153
  interface Options {
154
154
  rtt?: number;
155
155
  throughput?: number;
156
+ observedThroughput: number;
156
157
  maximumConcurrentRequests?: number;
157
158
  cpuSlowdownMultiplier?: number;
158
159
  layoutTaskMultiplier?: number;