lighthouse 12.2.1 → 12.2.2

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 (65) hide show
  1. package/cli/printer.js +10 -5
  2. package/cli/test/smokehouse/frontends/lib.js +1 -1
  3. package/cli/test/smokehouse/frontends/smokehouse-bin.js +1 -1
  4. package/cli/test/smokehouse/report-assert.js +1 -1
  5. package/core/audits/byte-efficiency/render-blocking-resources.js +3 -3
  6. package/core/config/config-helpers.js +3 -3
  7. package/core/config/lr-mobile-config.js +5 -0
  8. package/core/gather/base-artifacts.js +2 -2
  9. package/core/gather/driver/network-monitor.d.ts +1 -1
  10. package/core/gather/driver/network-monitor.js +8 -5
  11. package/core/gather/driver/target-manager.js +4 -0
  12. package/core/lib/arbitrary-equality-map.js +2 -2
  13. package/core/runner.js +4 -4
  14. package/dist/report/flow.js +2 -2
  15. package/package.json +9 -9
  16. package/readme.md +3 -0
  17. package/shared/localization/locales/ar-XB.json +88 -85
  18. package/shared/localization/locales/ar.json +98 -95
  19. package/shared/localization/locales/bg.json +88 -85
  20. package/shared/localization/locales/ca.json +91 -88
  21. package/shared/localization/locales/cs.json +91 -88
  22. package/shared/localization/locales/da.json +94 -91
  23. package/shared/localization/locales/de.json +92 -89
  24. package/shared/localization/locales/el.json +92 -89
  25. package/shared/localization/locales/en-GB.json +89 -86
  26. package/shared/localization/locales/en-US.json +23 -20
  27. package/shared/localization/locales/en-XA.json +88 -85
  28. package/shared/localization/locales/en-XL.json +23 -20
  29. package/shared/localization/locales/es-419.json +92 -89
  30. package/shared/localization/locales/es.json +91 -88
  31. package/shared/localization/locales/fi.json +92 -89
  32. package/shared/localization/locales/fil.json +93 -90
  33. package/shared/localization/locales/fr.json +94 -91
  34. package/shared/localization/locales/he.json +97 -94
  35. package/shared/localization/locales/hi.json +92 -89
  36. package/shared/localization/locales/hr.json +90 -87
  37. package/shared/localization/locales/hu.json +90 -87
  38. package/shared/localization/locales/id.json +91 -88
  39. package/shared/localization/locales/it.json +90 -87
  40. package/shared/localization/locales/ja.json +90 -87
  41. package/shared/localization/locales/ko.json +90 -87
  42. package/shared/localization/locales/lt.json +90 -87
  43. package/shared/localization/locales/lv.json +91 -88
  44. package/shared/localization/locales/nl.json +90 -87
  45. package/shared/localization/locales/no.json +92 -89
  46. package/shared/localization/locales/pl.json +90 -87
  47. package/shared/localization/locales/pt-PT.json +111 -108
  48. package/shared/localization/locales/pt.json +97 -94
  49. package/shared/localization/locales/ro.json +94 -91
  50. package/shared/localization/locales/ru.json +93 -90
  51. package/shared/localization/locales/sk.json +93 -90
  52. package/shared/localization/locales/sl.json +91 -88
  53. package/shared/localization/locales/sr-Latn.json +91 -88
  54. package/shared/localization/locales/sr.json +91 -88
  55. package/shared/localization/locales/sv.json +92 -89
  56. package/shared/localization/locales/ta.json +101 -98
  57. package/shared/localization/locales/te.json +92 -89
  58. package/shared/localization/locales/th.json +95 -92
  59. package/shared/localization/locales/tr.json +91 -88
  60. package/shared/localization/locales/uk.json +93 -90
  61. package/shared/localization/locales/vi.json +95 -92
  62. package/shared/localization/locales/zh-HK.json +92 -89
  63. package/shared/localization/locales/zh-TW.json +98 -95
  64. package/shared/localization/locales/zh.json +96 -93
  65. package/shared/localization/swap-locale.js +4 -4
package/cli/printer.js CHANGED
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import fs from 'fs';
8
+ import path from 'path';
8
9
 
9
10
  import log from 'lighthouse-logger';
10
11
 
@@ -58,13 +59,17 @@ function writeToStdout(output) {
58
59
  */
59
60
  function writeFile(filePath, output, outputMode) {
60
61
  return new Promise((resolve, reject) => {
61
- // TODO: make this mkdir to the filePath.
62
- fs.writeFile(filePath, output, (err) => {
63
- if (err) {
62
+ fs.mkdir(path.dirname(filePath), {recursive: true}, (err) => {
63
+ if (err && err.code !== 'EEXIST') {
64
64
  return reject(err);
65
65
  }
66
- log.log('Printer', `${OutputMode[outputMode]} output written to ${filePath}`);
67
- resolve();
66
+ fs.writeFile(filePath, output, (err) => {
67
+ if (err) {
68
+ return reject(err);
69
+ }
70
+ log.log('Printer', `${OutputMode[outputMode]} output written to ${filePath}`);
71
+ resolve();
72
+ });
68
73
  });
69
74
  });
70
75
  }
@@ -12,7 +12,7 @@
12
12
 
13
13
  /* eslint-disable no-console */
14
14
 
15
- import cloneDeep from 'lodash/cloneDeep.js';
15
+ import {cloneDeep} from 'lodash-es';
16
16
 
17
17
  import smokeTests from '../core-tests.js';
18
18
  import {runSmokehouse, getShardedDefinitions} from '../smokehouse.js';
@@ -16,7 +16,7 @@ import path from 'path';
16
16
  import fs from 'fs';
17
17
  import url from 'url';
18
18
 
19
- import cloneDeep from 'lodash/cloneDeep.js';
19
+ import {cloneDeep} from 'lodash-es';
20
20
  import yargs from 'yargs';
21
21
  import * as yargsHelpers from 'yargs/helpers';
22
22
  import log from 'lighthouse-logger';
@@ -9,7 +9,7 @@
9
9
  * against the results actually collected from Lighthouse.
10
10
  */
11
11
 
12
- import cloneDeep from 'lodash/cloneDeep.js';
12
+ import {cloneDeep} from 'lodash-es';
13
13
  import log from 'lighthouse-logger';
14
14
 
15
15
  import {LocalConsole} from './lib/local-console.js';
@@ -38,10 +38,10 @@ const str_ = i18n.createIcuMessageFn(import.meta.url, UIStrings);
38
38
  /**
39
39
  * Given a simulation's nodeTimings, return an object with the nodes/timing keyed by network URL
40
40
  * @param {LH.Gatherer.Simulation.Result['nodeTimings']} nodeTimings
41
- * @return {Map<string, {node: LH.Gatherer.Simulation.GraphNode, nodeTiming: LH.Gatherer.Simulation.NodeTiming}>}
41
+ * @return {Map<string, {node: LH.Gatherer.Simulation.GraphNetworkNode, nodeTiming: LH.Gatherer.Simulation.NodeTiming}>}
42
42
  */
43
43
  function getNodesAndTimingByRequestId(nodeTimings) {
44
- /** @type {Map<string, {node: LH.Gatherer.Simulation.GraphNode, nodeTiming: LH.Gatherer.Simulation.NodeTiming}>} */
44
+ /** @type {Map<string, {node: LH.Gatherer.Simulation.GraphNetworkNode, nodeTiming: LH.Gatherer.Simulation.NodeTiming}>} */
45
45
  const requestIdToNode = new Map();
46
46
 
47
47
  for (const [node, nodeTiming] of nodeTimings) {
@@ -169,7 +169,7 @@ class RenderBlockingResources extends Audit {
169
169
 
170
170
  results.push({
171
171
  url: resource.args.data.url,
172
- totalBytes: resource.args.data.encodedDataLength,
172
+ totalBytes: node.request.transferSize,
173
173
  wastedMs,
174
174
  });
175
175
  }
@@ -8,7 +8,7 @@ import path from 'path';
8
8
  import {createRequire} from 'module';
9
9
  import url from 'url';
10
10
 
11
- import isDeepEqual from 'lodash/isEqual.js';
11
+ import {isEqual} from 'lodash-es';
12
12
 
13
13
  import * as constants from './constants.js';
14
14
  import ConfigPlugin from './config-plugin.js';
@@ -69,7 +69,7 @@ const mergeOptionsOfItems = function(items) {
69
69
  * - `null` is treated similarly to `undefined` for whether a value should be overridden.
70
70
  * - `overwriteArrays` controls array extension behavior:
71
71
  * - true: Arrays are overwritten without any merging or concatenation.
72
- * - false: Arrays are concatenated and de-duped by isDeepEqual.
72
+ * - false: Arrays are concatenated and de-duped by isEqual.
73
73
  * - Objects are recursively merged.
74
74
  * - If the `settings` key is encountered while traversing an object, its arrays are *always*
75
75
  * overridden, not concatenated. (`overwriteArrays` is flipped to `true`)
@@ -90,7 +90,7 @@ function _mergeConfigFragment(base, extension, overwriteArrays = false) {
90
90
  if (!Array.isArray(base)) throw new TypeError(`Expected array but got ${typeof base}`);
91
91
  const merged = base.slice();
92
92
  extension.forEach(item => {
93
- if (!merged.some(candidate => isDeepEqual(candidate, item))) merged.push(item);
93
+ if (!merged.some(candidate => isEqual(candidate, item))) merged.push(item);
94
94
  });
95
95
 
96
96
  return merged;
@@ -10,6 +10,11 @@ const config = {
10
10
  settings: {
11
11
  maxWaitForFcp: 15 * 1000,
12
12
  maxWaitForLoad: 35 * 1000,
13
+ throttling: {
14
+ // Determined using PSI CPU benchmark median and
15
+ // https://lighthouse-cpu-throttling-calculator.vercel.app/
16
+ cpuSlowdownMultiplier: 1.5,
17
+ },
13
18
  skipAudits: [
14
19
  // Skip the h2 audit so it doesn't lie to us. See https://github.com/GoogleChrome/lighthouse/issues/6539
15
20
  'uses-http2',
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import log from 'lighthouse-logger';
8
- import isDeepEqual from 'lodash/isEqual.js';
8
+ import {isEqual} from 'lodash-es';
9
9
 
10
10
  import {
11
11
  getBrowserVersion, getBenchmarkIndex, getEnvironmentWarnings,
@@ -52,7 +52,7 @@ function deduplicateWarnings(warnings) {
52
52
  const unique = [];
53
53
 
54
54
  for (const warning of warnings) {
55
- if (unique.some(existing => isDeepEqual(warning, existing))) continue;
55
+ if (unique.some(existing => isEqual(warning, existing))) continue;
56
56
  unique.push(warning);
57
57
  }
58
58
 
@@ -71,7 +71,7 @@ export class NetworkMonitor extends NetworkMonitor_base {
71
71
  * @param {(request: NetworkRequest) => boolean} [requestFilter]
72
72
  * @return {boolean}
73
73
  */
74
- _isActiveIdlePeriod(allowedRequests: number, requestFilter?: ((request: NetworkRequest) => boolean) | undefined): boolean;
74
+ _isIdlePeriod(allowedRequests: number, requestFilter?: ((request: NetworkRequest) => boolean) | undefined): boolean;
75
75
  /**
76
76
  * Emits the appropriate network status event.
77
77
  */
@@ -129,7 +129,7 @@ class NetworkMonitor extends NetworkMonitorEventEmitter {
129
129
  * Returns whether the network is completely idle (i.e. there are 0 inflight network requests).
130
130
  */
131
131
  isIdle() {
132
- return this._isActiveIdlePeriod(0);
132
+ return this._isIdlePeriod(0);
133
133
  }
134
134
 
135
135
  /**
@@ -144,10 +144,13 @@ class NetworkMonitor extends NetworkMonitorEventEmitter {
144
144
  const rootFrameRequest = requests.find(r => r.resourceType === 'Document');
145
145
  const rootFrameId = rootFrameRequest?.frameId;
146
146
 
147
- return this._isActiveIdlePeriod(
147
+ return this._isIdlePeriod(
148
148
  0,
149
+ // Return true if it should be a candidate for critical.
149
150
  request =>
150
151
  request.frameId === rootFrameId &&
152
+ // WebSocket and Server-sent Events are typically long-lived and shouldn't be considered critical.
153
+ request.resourceType !== 'WebSocket' && request.resourceType !== 'EventSource' &&
151
154
  (request.priority === 'VeryHigh' || request.priority === 'High')
152
155
  );
153
156
  }
@@ -156,7 +159,7 @@ class NetworkMonitor extends NetworkMonitorEventEmitter {
156
159
  * Returns whether the network is semi-idle (i.e. there are 2 or fewer inflight network requests).
157
160
  */
158
161
  is2Idle() {
159
- return this._isActiveIdlePeriod(2);
162
+ return this._isIdlePeriod(2);
160
163
  }
161
164
 
162
165
  /**
@@ -166,7 +169,7 @@ class NetworkMonitor extends NetworkMonitorEventEmitter {
166
169
  * @param {(request: NetworkRequest) => boolean} [requestFilter]
167
170
  * @return {boolean}
168
171
  */
169
- _isActiveIdlePeriod(allowedRequests, requestFilter) {
172
+ _isIdlePeriod(allowedRequests, requestFilter) {
170
173
  if (!this._networkRecorder) return false;
171
174
  const requests = this._networkRecorder.getRawRecords();
172
175
  let inflightRequests = 0;
@@ -174,7 +177,7 @@ class NetworkMonitor extends NetworkMonitorEventEmitter {
174
177
  for (let i = 0; i < requests.length; i++) {
175
178
  const request = requests[i];
176
179
  if (request.finished) continue;
177
- if (requestFilter && !requestFilter(request)) continue;
180
+ if (requestFilter?.(request) === false) continue;
178
181
  if (NetworkRequest.isNonNetworkRequest(request)) continue;
179
182
  inflightRequests++;
180
183
  }
@@ -170,6 +170,10 @@ class TargetManager extends ProtocolEventEmitter {
170
170
  // Sometimes targets can be closed before we even have a chance to listen to their network activity.
171
171
  if (/Target closed/.test(err.message)) return;
172
172
 
173
+ // `Target.getTargetInfo` is not implemented for certain target types.
174
+ // Lighthouse isn't interested in these targets anyway so we can just ignore them.
175
+ if (/'Target.getTargetInfo' wasn't found/.test(err)) return;
176
+
173
177
  // Worker targets can be a bit fickle and we only enable them for diagnostic purposes.
174
178
  // We shouldn't throw a fatal error if there were issues attaching to them.
175
179
  if (targetType === 'worker') {
@@ -4,7 +4,7 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
 
7
- import isDeepEqual from 'lodash/isEqual.js';
7
+ import {isEqual} from 'lodash-es';
8
8
 
9
9
  /**
10
10
  * @fileoverview This class is designed to allow maps with arbitrary equality functions.
@@ -73,7 +73,7 @@ class ArbitraryEqualityMap {
73
73
  * @return {boolean}
74
74
  */
75
75
  static deepEquals(objA, objB) {
76
- return isDeepEqual(objA, objB);
76
+ return isEqual(objA, objB);
77
77
  }
78
78
  }
79
79
 
package/core/runner.js CHANGED
@@ -9,7 +9,7 @@ import path from 'path';
9
9
 
10
10
 
11
11
  import log from 'lighthouse-logger';
12
- import isDeepEqual from 'lodash/isEqual.js';
12
+ import {isEqual} from 'lodash-es';
13
13
 
14
14
  import {ReportScoring} from './scoring.js';
15
15
  import {Audit} from './audits/audit.js';
@@ -308,7 +308,7 @@ class Runner {
308
308
  ...Object.keys(normalizedAuditSettings),
309
309
  ]);
310
310
  for (const k of keys) {
311
- if (!isDeepEqual(normalizedGatherSettings[k], normalizedAuditSettings[k])) {
311
+ if (!isEqual(normalizedGatherSettings[k], normalizedAuditSettings[k])) {
312
312
  throw new Error(
313
313
  `Cannot change settings between gathering and auditing…
314
314
  Difference found at: \`${k}\`
@@ -318,8 +318,8 @@ vs
318
318
  }
319
319
  }
320
320
 
321
- // Call `isDeepEqual` on the entire thing, just in case something was missed.
322
- if (!isDeepEqual(normalizedGatherSettings, normalizedAuditSettings)) {
321
+ // Call `isEqual` on the entire thing, just in case something was missed.
322
+ if (!isEqual(normalizedGatherSettings, normalizedAuditSettings)) {
323
323
  throw new Error('Cannot change settings between gathering and auditing');
324
324
  }
325
325
  }