lighthouse 8.6.0 → 9.0.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 (209) hide show
  1. package/dist/report/bundle.esm.js +5994 -0
  2. package/dist/report/flow.js +30 -13
  3. package/dist/report/standalone.js +41 -35
  4. package/flow-report/.eslintrc.cjs +2 -0
  5. package/flow-report/assets/standalone-flow-template.html +3 -2
  6. package/flow-report/assets/styles.css +108 -31
  7. package/flow-report/src/app.tsx +18 -18
  8. package/flow-report/src/common.tsx +28 -15
  9. package/flow-report/src/header.tsx +12 -13
  10. package/flow-report/src/help-dialog.tsx +3 -4
  11. package/flow-report/src/i18n/i18n.tsx +57 -16
  12. package/flow-report/src/i18n/ui-strings.js +50 -0
  13. package/flow-report/src/icons.tsx +36 -8
  14. package/flow-report/src/sidebar/flow.tsx +3 -3
  15. package/flow-report/src/sidebar/sidebar.tsx +35 -14
  16. package/flow-report/src/summary/category.tsx +97 -24
  17. package/flow-report/src/summary/summary.tsx +21 -14
  18. package/flow-report/src/topbar.tsx +9 -5
  19. package/flow-report/src/util.ts +33 -26
  20. package/flow-report/src/wrappers/category-score.tsx +0 -3
  21. package/flow-report/src/wrappers/markdown.tsx +27 -0
  22. package/flow-report/src/wrappers/report-renderer.tsx +10 -3
  23. package/flow-report/src/wrappers/report.tsx +27 -6
  24. package/flow-report/standalone-flow.tsx +4 -3
  25. package/flow-report/test/common-test.tsx +32 -17
  26. package/flow-report/test/flow-report-pptr-test.ts +46 -0
  27. package/flow-report/test/header-test.tsx +6 -6
  28. package/flow-report/test/setup/env-setup.ts +1 -1
  29. package/flow-report/test/sidebar/sidebar-test.tsx +43 -1
  30. package/flow-report/test/summary/category-test.tsx +120 -24
  31. package/flow-report/test/summary/summary-test.tsx +1 -1
  32. package/flow-report/test/topbar-test.tsx +1 -0
  33. package/flow-report/test/util-test.tsx +32 -11
  34. package/flow-report/test/wrappers/category-score-test.tsx +87 -0
  35. package/flow-report/test/wrappers/markdown-test.tsx +29 -0
  36. package/flow-report/tsconfig.json +1 -0
  37. package/jest.config.js +4 -2
  38. package/lighthouse-cli/.eslintrc.cjs +2 -0
  39. package/lighthouse-cli/cli-flags.js +1 -1
  40. package/lighthouse-cli/run.js +1 -1
  41. package/lighthouse-cli/test/smokehouse/frontends/smokehouse-bin.js +0 -0
  42. package/lighthouse-cli/test/smokehouse/lighthouse-runners/bundle.js +4 -2
  43. package/lighthouse-cli/test/smokehouse/lighthouse-runners/cli.js +1 -1
  44. package/lighthouse-cli/test/smokehouse/smokehouse.js +1 -1
  45. package/lighthouse-core/audits/accessibility/axe-audit.js +7 -1
  46. package/lighthouse-core/audits/audit.js +1 -1
  47. package/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js +2 -0
  48. package/lighthouse-core/audits/byte-efficiency/modern-image-formats.js +4 -2
  49. package/lighthouse-core/audits/byte-efficiency/offscreen-images.js +11 -10
  50. package/lighthouse-core/audits/byte-efficiency/uses-optimized-images.js +5 -3
  51. package/lighthouse-core/audits/byte-efficiency/uses-responsive-images-snapshot.js +2 -1
  52. package/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js +2 -1
  53. package/lighthouse-core/audits/deprecations.js +33 -11
  54. package/lighthouse-core/audits/dobetterweb/uses-http2.js +27 -11
  55. package/lighthouse-core/audits/errors-in-console.js +0 -2
  56. package/lighthouse-core/audits/image-aspect-ratio.js +5 -5
  57. package/lighthouse-core/audits/image-size-responsive.js +6 -6
  58. package/lighthouse-core/audits/installable-manifest.js +5 -3
  59. package/lighthouse-core/audits/preload-lcp-image.js +7 -5
  60. package/lighthouse-core/audits/script-treemap-data.js +1 -1
  61. package/lighthouse-core/audits/unsized-images.js +2 -3
  62. package/lighthouse-core/computed/image-records.js +4 -3
  63. package/lighthouse-core/computed/metrics/lantern-total-blocking-time.js +3 -4
  64. package/lighthouse-core/computed/metrics/tbt-utils.js +57 -0
  65. package/lighthouse-core/computed/metrics/total-blocking-time.js +3 -53
  66. package/lighthouse-core/computed/resource-summary.js +1 -1
  67. package/lighthouse-core/config/config-helpers.js +21 -10
  68. package/lighthouse-core/config/constants.js +3 -4
  69. package/lighthouse-core/config/default-config.js +61 -71
  70. package/lighthouse-core/fraggle-rock/config/config.js +1 -1
  71. package/lighthouse-core/fraggle-rock/config/default-config.js +4 -5
  72. package/lighthouse-core/fraggle-rock/gather/base-gatherer.js +6 -1
  73. package/lighthouse-core/fraggle-rock/gather/session.js +3 -4
  74. package/lighthouse-core/gather/connections/cri.js +1 -1
  75. package/lighthouse-core/gather/driver/storage.js +0 -1
  76. package/lighthouse-core/gather/driver.js +3 -7
  77. package/lighthouse-core/gather/fetcher.js +4 -7
  78. package/lighthouse-core/gather/gather-runner.js +29 -6
  79. package/lighthouse-core/gather/gatherers/accessibility.js +27 -0
  80. package/lighthouse-core/gather/gatherers/dobetterweb/response-compression.js +1 -0
  81. package/lighthouse-core/gather/gatherers/image-elements.js +0 -3
  82. package/lighthouse-core/gather/gatherers/inspector-issues.js +5 -0
  83. package/lighthouse-core/lib/asset-saver.js +7 -4
  84. package/lighthouse-core/lib/emulation.js +45 -1
  85. package/lighthouse-core/lib/i18n/i18n.js +19 -8
  86. package/lighthouse-core/lib/lh-env.js +2 -0
  87. package/lighthouse-core/lib/proto-preprocessor.js +14 -2
  88. package/lighthouse-core/lib/tappable-rects.js +8 -15
  89. package/lighthouse-core/lib/url-shim.js +1 -1
  90. package/lighthouse-core/runner.js +1 -1
  91. package/lighthouse-core/util-commonjs.js +65 -46
  92. package/package.json +27 -17
  93. package/readme.md +3 -3
  94. package/report/.eslintrc.cjs +2 -0
  95. package/report/README.md +1 -1
  96. package/report/assets/standalone-template.html +2 -3
  97. package/report/assets/styles.css +360 -254
  98. package/report/assets/templates.html +21 -76
  99. package/report/clients/bundle.js +1 -0
  100. package/report/clients/standalone.js +6 -15
  101. package/report/generator/README.md +1 -1
  102. package/report/renderer/api.js +32 -0
  103. package/report/renderer/category-renderer.js +59 -19
  104. package/report/renderer/components.js +59 -110
  105. package/report/renderer/crc-details-renderer.js +15 -12
  106. package/report/renderer/dom.js +16 -1
  107. package/report/renderer/drop-down-menu.js +2 -2
  108. package/report/renderer/element-screenshot-renderer.js +8 -8
  109. package/report/renderer/features-util.js +1 -1
  110. package/report/renderer/open-tab.js +9 -3
  111. package/report/renderer/performance-category-renderer.js +55 -34
  112. package/report/renderer/pwa-category-renderer.js +0 -10
  113. package/report/renderer/report-renderer.js +91 -44
  114. package/report/renderer/report-ui-features.js +36 -33
  115. package/report/renderer/swap-locale-feature.js +3 -3
  116. package/report/renderer/topbar-features.js +53 -48
  117. package/report/renderer/util.js +66 -46
  118. package/report/test/clients/bundle-test.js +70 -0
  119. package/report/test/renderer/category-renderer-test.js +48 -3
  120. package/report/test/renderer/i18n-test.js +0 -7
  121. package/report/test/renderer/performance-category-renderer-test.js +51 -14
  122. package/report/test/renderer/pwa-category-renderer-test.js +6 -6
  123. package/report/test/renderer/report-renderer-axe-test.js +10 -12
  124. package/report/test/renderer/report-renderer-test.js +23 -22
  125. package/report/test/renderer/report-ui-features-test.js +20 -10
  126. package/report/test/renderer/text-encoding-test.js +1 -1
  127. package/report/test/renderer/util-test.js +35 -31
  128. package/report/test-assets/faux-psi-template.html +3 -11
  129. package/report/test-assets/faux-psi.js +26 -22
  130. package/report/types/html-renderer.d.ts +2 -0
  131. package/report/types/report-renderer.d.ts +23 -0
  132. package/shared/localization/format.js +64 -30
  133. package/shared/localization/locales/ar-XB.json +72 -75
  134. package/shared/localization/locales/ar.json +72 -75
  135. package/shared/localization/locales/bg.json +72 -75
  136. package/shared/localization/locales/ca.json +72 -75
  137. package/shared/localization/locales/cs.json +89 -92
  138. package/shared/localization/locales/da.json +72 -75
  139. package/shared/localization/locales/de.json +89 -92
  140. package/shared/localization/locales/el.json +72 -75
  141. package/shared/localization/locales/en-GB.json +72 -75
  142. package/shared/localization/locales/en-US.json +75 -75
  143. package/shared/localization/locales/en-XA.json +72 -75
  144. package/shared/localization/locales/en-XL.json +75 -75
  145. package/shared/localization/locales/es-419.json +90 -93
  146. package/shared/localization/locales/es.json +90 -93
  147. package/shared/localization/locales/fi.json +72 -75
  148. package/shared/localization/locales/fil.json +72 -75
  149. package/shared/localization/locales/fr.json +89 -92
  150. package/shared/localization/locales/he.json +73 -76
  151. package/shared/localization/locales/hi.json +72 -75
  152. package/shared/localization/locales/hr.json +72 -75
  153. package/shared/localization/locales/hu.json +89 -92
  154. package/shared/localization/locales/id.json +89 -92
  155. package/shared/localization/locales/it.json +89 -92
  156. package/shared/localization/locales/ja.json +89 -92
  157. package/shared/localization/locales/ko.json +89 -92
  158. package/shared/localization/locales/lt.json +89 -92
  159. package/shared/localization/locales/lv.json +95 -98
  160. package/shared/localization/locales/nl.json +89 -92
  161. package/shared/localization/locales/no.json +72 -75
  162. package/shared/localization/locales/pl.json +72 -75
  163. package/shared/localization/locales/pt-PT.json +72 -75
  164. package/shared/localization/locales/pt.json +89 -92
  165. package/shared/localization/locales/ro.json +90 -93
  166. package/shared/localization/locales/ru.json +89 -92
  167. package/shared/localization/locales/sk.json +89 -92
  168. package/shared/localization/locales/sl.json +89 -92
  169. package/shared/localization/locales/sr-Latn.json +89 -92
  170. package/shared/localization/locales/sr.json +89 -92
  171. package/shared/localization/locales/sv.json +72 -75
  172. package/shared/localization/locales/ta.json +89 -92
  173. package/shared/localization/locales/te.json +89 -92
  174. package/shared/localization/locales/th.json +89 -92
  175. package/shared/localization/locales/tr.json +89 -92
  176. package/shared/localization/locales/uk.json +92 -95
  177. package/shared/localization/locales/vi.json +89 -92
  178. package/shared/localization/locales/zh-HK.json +89 -92
  179. package/shared/localization/locales/zh-TW.json +89 -92
  180. package/shared/localization/locales/zh.json +89 -92
  181. package/shared/localization/locales.js +6 -0
  182. package/shared/test/localization/format-test.js +45 -9
  183. package/shared/test/localization/swap-locale-test.js +0 -12
  184. package/third-party/chromium-synchronization/inspector-issueAdded-types-test.js +19 -11
  185. package/third-party/chromium-synchronization/installability-errors-test.js +2 -0
  186. package/third-party/download-content-shell/download-content-shell.js +2 -2
  187. package/third-party/download-content-shell/utils.js +0 -24
  188. package/tsconfig-all.json +2 -2
  189. package/tsconfig.json +0 -1
  190. package/types/artifacts.d.ts +7 -7
  191. package/types/enquirer.d.ts +3 -1
  192. package/types/lhr/audit-details.d.ts +6 -5
  193. package/types/lhr/flow.d.ts +3 -2
  194. package/types/lhr/lhr.d.ts +1 -1
  195. package/types/node.d.ts +5 -5
  196. package/types/rollup-plugin-postprocess.d.ts +10 -0
  197. package/changelog.md +0 -5490
  198. package/lighthouse-core/audits/dobetterweb/appcache-manifest.js +0 -67
  199. package/lighthouse-core/audits/dobetterweb/external-anchors-use-rel-noopener.js +0 -96
  200. package/lighthouse-core/audits/redirects-http.js +0 -59
  201. package/lighthouse-core/gather/gatherers/dobetterweb/appcache.js +0 -34
  202. package/lighthouse-core/gather/gatherers/http-redirect.js +0 -46
  203. package/lighthouse-core/lib/i18n/locales/en-US.ctc.json +0 -6699
  204. package/lighthouse-core/lib/i18n/locales/en-XL.ctc.json +0 -6672
  205. package/lighthouse-core/scripts/package.json +0 -4
  206. package/report/clients/psi.js +0 -158
  207. package/report/test/clients/psi-test.js +0 -143
  208. package/shared/localization/locales/en-US.ctc.json +0 -6877
  209. package/shared/localization/locales/en-XL.ctc.json +0 -6852
@@ -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';
@@ -235,9 +238,9 @@ async function saveTrace(traceData, traceFilename) {
235
238
  const traceIter = traceJsonGenerator(traceData);
236
239
  const writeStream = fs.createWriteStream(traceFilename);
237
240
 
238
- // TODO: Can remove Readable.from() in Node 13, promisify(pipeline) in Node 15.
241
+ // TODO: Can remove promisify(pipeline) in Node 15.
239
242
  // https://nodejs.org/api/stream.html#stream_stream_pipeline_streams_callback
240
- return pipeline(stream.Readable.from(traceIter), writeStream);
243
+ return pipeline(traceIter, writeStream);
241
244
  }
242
245
 
243
246
  /**
@@ -250,7 +253,7 @@ function saveDevtoolsLog(devtoolsLog, devtoolLogFilename) {
250
253
  const logIter = arrayOfObjectsJsonGenerator(devtoolsLog);
251
254
  const writeStream = fs.createWriteStream(devtoolLogFilename);
252
255
 
253
- return pipeline(stream.Readable.from(logIter), writeStream);
256
+ return pipeline(logIter, writeStream);
254
257
  }
255
258
 
256
259
  /**
@@ -5,6 +5,8 @@
5
5
  */
6
6
  'use strict';
7
7
 
8
+ const {version: lighthouseVersion} = require('../../package.json');
9
+
8
10
  const NO_THROTTLING_METRICS = {
9
11
  latency: 0,
10
12
  downloadThroughput: 0,
@@ -16,6 +18,46 @@ const NO_CPU_THROTTLE_METRICS = {
16
18
  rate: 1,
17
19
  };
18
20
 
21
+ /**
22
+ * @param {string} userAgent
23
+ * @param {LH.Config.Settings['formFactor']} formFactor
24
+ * @return {LH.Crdp.Emulation.SetUserAgentOverrideRequest['userAgentMetadata']}
25
+ */
26
+ function parseUseragentIntoMetadata(userAgent, formFactor) {
27
+ const match = userAgent.match(/Chrome\/([\d.]+)/); // eg 'Chrome/(71.0.3577.0)'
28
+ const fullVersion = (match && match[1]) || '99.0.1234.0';
29
+ const [version] = fullVersion.split('.', 1);
30
+ const brands = [
31
+ {brand: 'Chromium', version},
32
+ {brand: 'Google Chrome', version},
33
+ {brand: 'Lighthouse', version: lighthouseVersion},
34
+ ];
35
+
36
+ const motoG4Details = {
37
+ platform: 'Android',
38
+ platformVersion: '6.0',
39
+ architecture: '',
40
+ model: 'Moto G4',
41
+ };
42
+ const macDesktopDetails = {
43
+ platform: 'macOS',
44
+ platformVersion: '10.15.7',
45
+ architecture: 'x86',
46
+ model: '',
47
+ };
48
+ const mobile = formFactor === 'mobile';
49
+
50
+ return {
51
+ brands,
52
+ fullVersion,
53
+ // Since config users can supply a custom useragent, they likely are emulating something
54
+ // other than Moto G4 and MacOS Desktop.
55
+ // TODO: Determine how to thoughtfully expose this metadata/client-hints configurability.
56
+ ...(mobile ? motoG4Details : macDesktopDetails),
57
+ mobile,
58
+ };
59
+ }
60
+
19
61
  /**
20
62
  * @param {LH.Gatherer.FRProtocolSession} session
21
63
  * @param {LH.Config.Settings} settings
@@ -23,8 +65,10 @@ const NO_CPU_THROTTLE_METRICS = {
23
65
  */
24
66
  async function emulate(session, settings) {
25
67
  if (settings.emulatedUserAgent !== false) {
68
+ const userAgent = /** @type {string} */ (settings.emulatedUserAgent);
26
69
  await session.sendCommand('Network.setUserAgentOverride', {
27
- userAgent: /** @type {string} */ (settings.emulatedUserAgent),
70
+ userAgent,
71
+ userAgentMetadata: parseUseragentIntoMetadata(userAgent, settings.formFactor),
28
72
  });
29
73
  }
30
74
  // See devtools-entry for one usecase for disabling screenEmulation
@@ -12,9 +12,11 @@ const lookupClosestLocale = require('lookup-closest-locale');
12
12
  const {getAvailableLocales} = require('../../../shared/localization/format.js');
13
13
  const log = require('lighthouse-logger');
14
14
  const {LH_ROOT} = require('../../../root.js');
15
- const {isIcuMessage, _formatMessage} = require('../../../shared/localization/format.js');
16
-
17
- const DEFAULT_LOCALE = 'en';
15
+ const {
16
+ isIcuMessage,
17
+ formatMessage,
18
+ DEFAULT_LOCALE,
19
+ } = require('../../../shared/localization/format.js');
18
20
 
19
21
  const UIStrings = {
20
22
  /** Used to show the duration in milliseconds that something lasted. The `{timeInMs}` placeholder will be replaced with the time duration, shown in milliseconds (e.g. 63 ms) */
@@ -118,23 +120,32 @@ const UIStrings = {
118
120
  * - supported locales in Intl formatters
119
121
  *
120
122
  * If `locale` isn't provided or one could not be found, DEFAULT_LOCALE is returned.
123
+ *
124
+ * By default any of the locales Lighthouse has strings for can be returned, but this
125
+ * can be overriden with `possibleLocales`, useful e.g. when Lighthouse is bundled and
126
+ * only DEFAULT_LOCALE is available, but `possibleLocales` can be used to select a
127
+ * locale available to be downloaded on demand.
121
128
  * @param {string|string[]=} locales
129
+ * @param {Array<string>=} possibleLocales
122
130
  * @return {LH.Locale}
123
131
  */
124
- function lookupLocale(locales) {
125
- // If Node was built with `--with-intl=none`, `Intl` won't exist.
132
+ function lookupLocale(locales, possibleLocales) {
133
+ // TODO: lookupLocale may need to be split into two functions, one that canonicalizes
134
+ // locales and one that looks up the best locale filename for a given locale.
135
+ // e.g. `en-IE` is canonical, but uses `en-GB.json`. See TODO in locales.js
136
+
126
137
  if (typeof Intl !== 'object') {
138
+ // If Node was built with `--with-intl=none`, `Intl` won't exist.
127
139
  throw new Error('Lighthouse must be run in Node with `Intl` support. See https://nodejs.org/api/intl.html for help');
128
140
  }
129
141
 
130
- // TODO: could do more work to sniff out the user's locale
131
142
  const canonicalLocales = Intl.getCanonicalLocales(locales);
132
143
 
133
144
  // Filter by what's available in this runtime.
134
145
  const availableLocales = Intl.NumberFormat.supportedLocalesOf(canonicalLocales);
135
146
 
136
147
  // Get available locales and transform into object to match `lookupClosestLocale`'s API.
137
- const localesWithMessages = getAvailableLocales();
148
+ const localesWithMessages = possibleLocales || getAvailableLocales();
138
149
  const localesWithmessagesObj = /** @type {Record<LH.Locale, LhlMessages>} */ (
139
150
  Object.fromEntries(localesWithMessages.map(l => [l, {}])));
140
151
 
@@ -182,7 +193,7 @@ function createIcuMessageFn(filename, fileStrings) {
182
193
  return {
183
194
  i18nId,
184
195
  values,
185
- formattedDefault: _formatMessage(message, values, DEFAULT_LOCALE),
196
+ formattedDefault: formatMessage(message, values, DEFAULT_LOCALE),
186
197
  };
187
198
  };
188
199
 
@@ -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
@@ -29,10 +29,22 @@ function processForProto(lhr) {
29
29
  // 'ignore unknown fields' in the language of conversion.
30
30
  if (reportJson.configSettings) {
31
31
  // The settings that are in both proto and LHR
32
- const {formFactor, locale, onlyCategories, channel} = reportJson.configSettings;
32
+ const {
33
+ formFactor,
34
+ locale,
35
+ onlyCategories,
36
+ channel,
37
+ throttling,
38
+ throttlingMethod} = reportJson.configSettings;
33
39
 
34
40
  // @ts-expect-error - intentionally only a subset of settings.
35
- reportJson.configSettings = {formFactor, locale, onlyCategories, channel};
41
+ reportJson.configSettings = {
42
+ formFactor,
43
+ locale,
44
+ onlyCategories,
45
+ channel,
46
+ throttling,
47
+ throttlingMethod};
36
48
  }
37
49
 
38
50
  // Remove runtimeError if it is NO_ERROR
@@ -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
@@ -9,7 +9,7 @@
9
9
  * URL shim so we keep our code DRY
10
10
  */
11
11
 
12
- const Util = require('../util-commonjs.js');
12
+ const {Util} = require('../util-commonjs.js');
13
13
 
14
14
  /** @typedef {import('./network-request.js')} NetworkRequest */
15
15
 
@@ -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.
@@ -42,6 +42,10 @@ const listOfTlds = [
42
42
  ];
43
43
 
44
44
  class Util {
45
+ /** @type {I18n<typeof UIStrings>} */
46
+ // @ts-expect-error: Is set in report renderer.
47
+ static i18n = null;
48
+
45
49
  static get PASS_THRESHOLD() {
46
50
  return PASS_THRESHOLD;
47
51
  }
@@ -107,6 +111,23 @@ class Util {
107
111
  /** @type {Map<string, Array<LH.ReportResult.AuditRef>>} */
108
112
  const relevantAuditToMetricsMap = new Map();
109
113
 
114
+ // This backcompat converts old LHRs (<9.0.0) to use the new "hidden" group.
115
+ // Old LHRs used "no group" to identify audits that should be hidden in performance instead of the "hidden" group.
116
+ // Newer LHRs use "no group" to identify opportunities and diagnostics whose groups are assigned by details type.
117
+ const [majorVersion] = clone.lighthouseVersion.split('.').map(Number);
118
+ const perfCategory = clone.categories['performance'];
119
+ if (majorVersion < 9 && perfCategory) {
120
+ if (!clone.categoryGroups) clone.categoryGroups = {};
121
+ clone.categoryGroups['hidden'] = {title: ''};
122
+ for (const auditRef of perfCategory.auditRefs) {
123
+ if (!auditRef.group) {
124
+ auditRef.group = 'hidden';
125
+ } else if (['load-opportunities', 'diagnostics'].includes(auditRef.group)) {
126
+ delete auditRef.group;
127
+ }
128
+ }
129
+ }
130
+
110
131
  for (const category of Object.values(clone.categories)) {
111
132
  // Make basic lookup table for relevantAudits
112
133
  category.auditRefs.forEach(metricRef => {
@@ -170,6 +191,8 @@ class Util {
170
191
 
171
192
  /**
172
193
  * Convert a score to a rating label.
194
+ * TODO: Return `'error'` for `score === null && !scoreDisplayMode`.
195
+ *
173
196
  * @param {number|null} score
174
197
  * @param {string=} scoreDisplayMode
175
198
  * @return {string}
@@ -390,43 +413,21 @@ class Util {
390
413
  return hostname.split('.').slice(-splitTld.length).join('.');
391
414
  }
392
415
 
393
- /**
394
- * @param {LH.Result['configSettings']} settings
395
- * @return {!Array<{name: string, description: string}>}
396
- */
397
- static getEnvironmentDisplayValues(settings) {
398
- const emulationDesc = Util.getEmulationDescriptions(settings);
399
-
400
- return [
401
- {
402
- name: Util.i18n.strings.runtimeSettingsDevice,
403
- description: emulationDesc.deviceEmulation,
404
- },
405
- {
406
- name: Util.i18n.strings.runtimeSettingsNetworkThrottling,
407
- description: emulationDesc.networkThrottling,
408
- },
409
- {
410
- name: Util.i18n.strings.runtimeSettingsCPUThrottling,
411
- description: emulationDesc.cpuThrottling,
412
- },
413
- ];
414
- }
415
416
 
416
417
  /**
417
418
  * @param {LH.Result['configSettings']} settings
418
- * @return {{deviceEmulation: string, networkThrottling: string, cpuThrottling: string}}
419
+ * @return {!{deviceEmulation: string, networkThrottling: string, cpuThrottling: string, summary: string}}
419
420
  */
420
421
  static getEmulationDescriptions(settings) {
421
422
  let cpuThrottling;
422
423
  let networkThrottling;
424
+ let summary;
423
425
 
424
426
  const throttling = settings.throttling;
425
427
 
426
428
  switch (settings.throttlingMethod) {
427
429
  case 'provided':
428
- cpuThrottling = Util.i18n.strings.throttlingProvided;
429
- networkThrottling = Util.i18n.strings.throttlingProvided;
430
+ summary = networkThrottling = cpuThrottling = Util.i18n.strings.throttlingProvided;
430
431
  break;
431
432
  case 'devtools': {
432
433
  const {cpuSlowdownMultiplier, requestLatencyMs} = throttling;
@@ -434,6 +435,13 @@ class Util {
434
435
  networkThrottling = `${Util.i18n.formatNumber(requestLatencyMs)}${NBSP}ms HTTP RTT, ` +
435
436
  `${Util.i18n.formatNumber(throttling.downloadThroughputKbps)}${NBSP}Kbps down, ` +
436
437
  `${Util.i18n.formatNumber(throttling.uploadThroughputKbps)}${NBSP}Kbps up (DevTools)`;
438
+
439
+ const isSlow4G = () => {
440
+ return requestLatencyMs === 150 * 3.75 &&
441
+ throttling.downloadThroughputKbps === 1.6 * 1024 * 0.9 &&
442
+ throttling.uploadThroughputKbps === 750 * 0.9;
443
+ };
444
+ summary = isSlow4G() ? Util.i18n.strings.runtimeSlow4g : Util.i18n.strings.runtimeCustom;
437
445
  break;
438
446
  }
439
447
  case 'simulate': {
@@ -441,11 +449,15 @@ class Util {
441
449
  cpuThrottling = `${Util.i18n.formatNumber(cpuSlowdownMultiplier)}x slowdown (Simulated)`;
442
450
  networkThrottling = `${Util.i18n.formatNumber(rttMs)}${NBSP}ms TCP RTT, ` +
443
451
  `${Util.i18n.formatNumber(throughputKbps)}${NBSP}Kbps throughput (Simulated)`;
452
+
453
+ const isSlow4G = () => {
454
+ return rttMs === 150 && throughputKbps === 1.6 * 1024;
455
+ };
456
+ summary = isSlow4G() ? Util.i18n.strings.runtimeSlow4g : Util.i18n.strings.runtimeCustom;
444
457
  break;
445
458
  }
446
459
  default:
447
- cpuThrottling = Util.i18n.strings.runtimeUnknown;
448
- networkThrottling = Util.i18n.strings.runtimeUnknown;
460
+ summary = cpuThrottling = networkThrottling = Util.i18n.strings.runtimeUnknown;
449
461
  }
450
462
 
451
463
  // TODO(paulirish): revise Runtime Settings strings: https://github.com/GoogleChrome/lighthouse/pull/11796
@@ -458,6 +470,7 @@ class Util {
458
470
  deviceEmulation,
459
471
  cpuThrottling,
460
472
  networkThrottling,
473
+ summary,
461
474
  };
462
475
  }
463
476
 
@@ -527,10 +540,9 @@ class Util {
527
540
  let totalWeight = 0;
528
541
  for (const auditRef of category.auditRefs) {
529
542
  const auditPassed = Util.showAsPassed(auditRef.result);
530
- const notDisplayed = !auditRef.group && category.id === 'performance';
531
543
 
532
544
  // Don't count the audit if it's manual, N/A, or isn't displayed.
533
- if (notDisplayed ||
545
+ if (auditRef.group === 'hidden' ||
534
546
  auditRef.result.scoreDisplayMode === 'manual' ||
535
547
  auditRef.result.scoreDisplayMode === 'notApplicable') {
536
548
  continue;
@@ -566,14 +578,10 @@ Util.getUniqueSuffix = (() => {
566
578
  };
567
579
  })();
568
580
 
569
- /** @type {I18n<typeof Util['UIStrings']>} */
570
- // @ts-expect-error: Is set in report renderer.
571
- Util.i18n = null;
572
-
573
581
  /**
574
582
  * Report-renderer-specific strings.
575
583
  */
576
- Util.UIStrings = {
584
+ const UIStrings = {
577
585
  /** Disclaimer shown to users below the metric values (First Contentful Paint, Time to Interactive, etc) to warn them that the numbers they see will likely change slightly the next time they run Lighthouse. */
578
586
  varianceDisclaimer: 'Values are estimated and may vary. The [performance score is calculated](https://web.dev/performance-scoring/) directly from these metrics.',
579
587
  /** Text link pointing to an interactive calculator that explains Lighthouse scoring. The link text should be fairly short. */
@@ -640,22 +648,12 @@ Util.UIStrings = {
640
648
  /** Option in a dropdown menu that toggles the themeing of the report between Light(default) and Dark themes. */
641
649
  dropdownDarkTheme: 'Toggle Dark Theme',
642
650
 
643
- /** Title of the Runtime settings table in a Lighthouse report. Runtime settings are the environment configurations that a specific report used at auditing time. */
644
- runtimeSettingsTitle: 'Runtime Settings',
645
- /** Label for a row in a table that shows the URL that was audited during a Lighthouse run. */
646
- runtimeSettingsUrl: 'URL',
647
- /** Label for a row in a table that shows the time at which a Lighthouse run was conducted; formatted as a timestamp, e.g. Jan 1, 1970 12:00 AM UTC. */
648
- runtimeSettingsFetchTime: 'Fetch Time',
649
651
  /** Label for a row in a table that describes the kind of device that was emulated for the Lighthouse run. Example values for row elements: 'No Emulation', 'Emulated Desktop', etc. */
650
652
  runtimeSettingsDevice: 'Device',
651
653
  /** Label for a row in a table that describes the network throttling conditions that were used during a Lighthouse run, if any. */
652
654
  runtimeSettingsNetworkThrottling: 'Network throttling',
653
655
  /** Label for a row in a table that describes the CPU throttling conditions that were used during a Lighthouse run, if any.*/
654
656
  runtimeSettingsCPUThrottling: 'CPU throttling',
655
- /** Label for a row in a table that shows in what tool Lighthouse is being run (e.g. The lighthouse CLI, Chrome DevTools, Lightrider, WebPageTest, etc). */
656
- runtimeSettingsChannel: 'Channel',
657
- /** Label for a row in a table that shows the User Agent that was detected on the Host machine that ran Lighthouse. */
658
- runtimeSettingsUA: 'User agent (host)',
659
657
  /** Label for a row in a table that shows the User Agent that was used to send out all network requests during the Lighthouse run. */
660
658
  runtimeSettingsUANetwork: 'User agent (network)',
661
659
  /** Label for a row in a table that shows the estimated CPU power of the machine running Lighthouse. Example row values: 532, 1492, 783. */
@@ -674,10 +672,31 @@ Util.UIStrings = {
674
672
  runtimeDesktopEmulation: 'Emulated Desktop',
675
673
  /** Descriptive explanation for a runtime setting that is set to an unknown value. */
676
674
  runtimeUnknown: 'Unknown',
675
+ /** Descriptive label that this analysis run was from a single pageload of a browser (not a summary of hundreds of loads) */
676
+ runtimeSingleLoad: 'Single page load',
677
+ /** Descriptive label that this analysis only considers the initial load of the page, and no interaction beyond when the page had "fully loaded" */
678
+ runtimeAnalysisWindow: 'Initial page load',
679
+ /** Descriptive explanation that this analysis run was from a single pageload of a browser, whereas field data often summarizes hundreds+ of page loads */
680
+ runtimeSingleLoadTooltip: 'This data is taken from a single page load, as opposed to field data summarizing many sessions.', // eslint-disable-line max-len
677
681
 
678
682
  /** Descriptive explanation for environment throttling that was provided by the runtime environment instead of provided by Lighthouse throttling. */
679
683
  throttlingProvided: 'Provided by environment',
684
+ /** Label for an interactive control that will reveal or hide a group of content. This control toggles between the text 'Show' and 'Hide'. */
685
+ show: 'Show',
686
+ /** Label for an interactive control that will reveal or hide a group of content. This control toggles between the text 'Show' and 'Hide'. */
687
+ hide: 'Hide',
688
+ /** Label for an interactive control that will reveal or hide a group of content. This control toggles between the text 'Expand view' and 'Collapse view'. */
689
+ expandView: 'Expand view',
690
+ /** Label for an interactive control that will reveal or hide a group of content. This control toggles between the text 'Expand view' and 'Collapse view'. */
691
+ collapseView: 'Collapse view',
692
+ /** Label indicating that Lighthouse throttled the page to emulate a slow 4G network connection. */
693
+ runtimeSlow4g: 'Slow 4G throttling',
694
+ /** Label indicating that Lighthouse throttled the page using custom throttling settings. */
695
+ runtimeCustom: 'Custom throttling',
680
696
  };
697
+ Util.UIStrings = UIStrings;
681
698
 
682
-
683
- module.exports = Util;
699
+ module.exports = {
700
+ Util,
701
+ UIStrings,
702
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lighthouse",
3
- "version": "8.6.0",
3
+ "version": "9.0.0",
4
4
  "description": "Automated auditing, performance metrics, and best practices for the web.",
5
5
  "main": "./lighthouse-core/index.js",
6
6
  "bin": {
@@ -9,9 +9,10 @@
9
9
  "smokehouse": "./lighthouse-cli/test/smokehouse/frontends/smokehouse-bin.js"
10
10
  },
11
11
  "engines": {
12
- "node": ">=12.20.0 12 || >=14.13 14 || >=15"
12
+ "node": ">=14.15"
13
13
  },
14
14
  "scripts": {
15
+ "prepack": "yarn build-report --standalone --flow --esm",
15
16
  "build-all": "npm-run-posix-or-windows build-all:task",
16
17
  "build-all:task": "yarn build-report && yarn build-cdt-lib && yarn build-devtools && (yarn build-extension & yarn build-lr & yarn build-viewer & yarn build-treemap & yarn build-smokehouse-bundle & wait) && yarn build-pack",
17
18
  "build-all:task:windows": "yarn build-report && yarn build-cdt-lib && yarn build-extension && yarn build-devtools && yarn build-lr && yarn build-viewer && yarn build-treemap && yarn build-smokehouse-bundle",
@@ -23,7 +24,7 @@
23
24
  "build-smokehouse-bundle": "node ./build/build-smokehouse-bundle.js",
24
25
  "build-lr": "yarn reset-link && node ./build/build-lightrider-bundles.js",
25
26
  "build-pack": "bash build/build-pack.sh",
26
- "build-report": "node build/build-report-components.js && yarn eslint --fix report/renderer/components.js && node build/build-report.js",
27
+ "build-report": "node build/build-report-components.js && yarn eslint --fix report/renderer/components.js && bash lighthouse-core/scripts/copy-util-commonjs.sh && node build/build-report.js",
27
28
  "build-sample-reports": "yarn build-report && node build/build-sample-reports.js",
28
29
  "build-treemap": "node ./build/build-treemap.js",
29
30
  "build-viewer": "node ./build/build-viewer.js",
@@ -38,8 +39,8 @@
38
39
  "test": "yarn diff:sample-json && yarn lint --quiet && yarn unit && yarn type-check",
39
40
  "test-bundle": "yarn smoke --runner bundle -j=1 --retries=2 --invert-match forms",
40
41
  "test-clients": "yarn jest \"$PWD/clients/\" && yarn jest --testMatch=\"**/clients/test/**/*-test-pptr.js\"",
41
- "test-viewer": "yarn unit-viewer && yarn jest --testMatch=\"**/lighthouse-viewer/**/*-test-pptr.js\"",
42
- "test-treemap": "yarn unit-treemap && yarn jest --testMatch=\"**/lighthouse-treemap/**/*-test-pptr.js\"",
42
+ "test-viewer": "yarn unit-viewer && yarn jest --testMatch=\"**/viewer/**/*-test-pptr.js\"",
43
+ "test-treemap": "yarn unit-treemap && yarn jest --testMatch=\"**/treemap/**/*-test-pptr.js\"",
43
44
  "test-lantern": "bash lighthouse-core/scripts/test-lantern.sh",
44
45
  "test-legacy-javascript": "bash lighthouse-core/scripts/test-legacy-javascript.sh",
45
46
  "test-docs": "yarn --cwd docs/recipes/ test",
@@ -47,11 +48,11 @@
47
48
  "unit-core": "yarn jest \"lighthouse-core\"",
48
49
  "unit-cli": "yarn jest \"lighthouse-cli/\"",
49
50
  "unit-report": "yarn jest \"report/\"",
50
- "unit-treemap": "yarn jest \"lighthouse-treemap/.*-test.js\"",
51
- "unit-viewer": "yarn jest \"lighthouse-viewer/.*-test.js\"",
51
+ "unit-treemap": "yarn jest \"treemap/.*-test.js\"",
52
+ "unit-viewer": "yarn jest \"viewer/.*-test.js\"",
52
53
  "unit-flow": "yarn jest \"flow-report/.*-test.[tj]s[x]?\"",
53
54
  "unit": "yarn jest",
54
- "unit:ci": "NODE_OPTIONS=--max-old-space-size=8192 npm run jest -- --ci",
55
+ "unit:ci": "NODE_OPTIONS=--max-old-space-size=8192 npm run jest --ci .",
55
56
  "core-unit": "yarn unit-core",
56
57
  "cli-unit": "yarn unit-cli",
57
58
  "viewer-unit": "yarn unit-viewer",
@@ -94,9 +95,16 @@
94
95
  },
95
96
  "devDependencies": {
96
97
  "@build-tracker/cli": "^1.0.0-beta.15",
98
+ "@firebase/app-types": "0.3.1",
99
+ "@firebase/auth-types": "0.3.2",
100
+ "@firebase/util": "0.2.1",
101
+ "@rollup/plugin-alias": "^3.1.2",
97
102
  "@rollup/plugin-commonjs": "^20.0.0",
103
+ "@rollup/plugin-dynamic-import-vars": "^1.1.1",
104
+ "@rollup/plugin-json": "^4.1.0",
98
105
  "@rollup/plugin-node-resolve": "^13.0.4",
99
106
  "@rollup/plugin-typescript": "^8.2.5",
107
+ "@stadtlandnetz/rollup-plugin-postprocess": "^1.1.0",
100
108
  "@testing-library/preact": "^2.0.1",
101
109
  "@testing-library/preact-hooks": "^1.1.0",
102
110
  "@types/archiver": "^2.1.2",
@@ -105,7 +113,7 @@
105
113
  "@types/configstore": "^4.0.0",
106
114
  "@types/cpy": "^5.1.0",
107
115
  "@types/eslint": "^4.16.6",
108
- "@types/exorcist": "^0.4.5",
116
+ "@types/estree": "^0.0.50",
109
117
  "@types/gh-pages": "^2.0.0",
110
118
  "@types/google.analytics": "0.0.39",
111
119
  "@types/jest": "^24.0.9",
@@ -127,11 +135,10 @@
127
135
  "@types/yargs-parser": "^15.0.0",
128
136
  "@typescript-eslint/eslint-plugin": "^4.30.0",
129
137
  "@typescript-eslint/parser": "^4.30.0",
130
- "@wardpeet/brfs": "2.1.0",
138
+ "acorn": "^8.5.0",
131
139
  "angular": "^1.7.4",
132
140
  "archiver": "^3.0.0",
133
141
  "browserify": "^17.0.0",
134
- "browserify-banner": "^1.0.15",
135
142
  "c8": "^7.4.0",
136
143
  "chalk": "^2.4.1",
137
144
  "chrome-devtools-frontend": "1.0.922924",
@@ -139,14 +146,13 @@
139
146
  "cpy": "^7.0.1",
140
147
  "cross-env": "^7.0.2",
141
148
  "csv-validator": "^0.0.3",
142
- "devtools-protocol": "0.0.901419",
149
+ "devtools-protocol": "0.0.939404",
143
150
  "es-main": "^1.0.2",
144
151
  "eslint": "^7.23.0",
145
152
  "eslint-config-google": "^0.9.1",
146
153
  "eslint-plugin-import": "^2.24.2",
147
154
  "eslint-plugin-local-rules": "0.1.0",
148
155
  "event-target-shim": "^6.0.2",
149
- "exorcist": "^1.0.1",
150
156
  "firebase": "^9.0.2",
151
157
  "gh-pages": "^2.0.1",
152
158
  "glob": "^7.1.3",
@@ -156,16 +162,17 @@
156
162
  "jsdom": "^12.2.0",
157
163
  "jsonld": "^5.2.0",
158
164
  "jsonlint-mod": "^1.7.6",
159
- "lighthouse-plugin-publisher-ads": "^1.4.1",
165
+ "lighthouse-plugin-publisher-ads": "^1.5.4",
166
+ "magic-string": "^0.25.7",
160
167
  "mime-types": "^2.1.30",
161
168
  "node-fetch": "^2.6.1",
162
169
  "npm-run-posix-or-windows": "^2.0.2",
163
- "package-json-versionify": "^1.0.4",
164
170
  "pako": "^2.0.3",
165
171
  "preact": "^10.5.14",
166
172
  "pretty-json-stringify": "^0.0.2",
167
173
  "puppeteer": "^10.2.0",
168
- "rollup": "^2.50.6",
174
+ "resolve": "^1.20.0",
175
+ "rollup": "^2.52.7",
169
176
  "rollup-plugin-node-resolve": "^5.2.0",
170
177
  "rollup-plugin-polyfill-node": "^0.7.0",
171
178
  "rollup-plugin-replace": "^2.2.0",
@@ -181,7 +188,7 @@
181
188
  },
182
189
  "dependencies": {
183
190
  "axe-core": "4.2.3",
184
- "chrome-launcher": "^0.14.0",
191
+ "chrome-launcher": "^0.15.0",
185
192
  "configstore": "^5.0.1",
186
193
  "csp_evaluator": "1.1.0",
187
194
  "cssstyle": "1.2.1",
@@ -211,6 +218,9 @@
211
218
  "yargs": "^16.1.1",
212
219
  "yargs-parser": "^20.2.4"
213
220
  },
221
+ "resolutions": {
222
+ "puppeteer/**/devtools-protocol": "0.0.939404"
223
+ },
214
224
  "repository": "GoogleChrome/lighthouse",
215
225
  "keywords": [
216
226
  "google",
package/readme.md CHANGED
@@ -52,7 +52,7 @@ The Chrome extension was available prior to Lighthouse being available in Chrome
52
52
 
53
53
  The Node CLI provides the most flexibility in how Lighthouse runs can be configured and reported. Users who want more advanced usage, or want to run Lighthouse in an automated fashion should use the Node CLI.
54
54
 
55
- _Lighthouse requires Node 12 LTS (12.20) or later._
55
+ _Lighthouse requires Node 14 LTS (14.x) or later._
56
56
 
57
57
  **Installation**:
58
58
 
@@ -451,9 +451,9 @@ machine. Report results are never processed or beaconed to a remote server.
451
451
 
452
452
  ### How do I get localized Lighthouse results via the CLI?
453
453
 
454
- Starting in Lighthouse 8.0, Lighthouse relies entirely on native `Intl` support and no longer uses an `Intl` polyfill. If you're using Node 13 or later, there should be no issue because Node is now [built with `full-icu` by default](https://nodejs.medium.com/node-js-12-to-lts-and-node-js-13-is-here-e28d6a4a2bd#9514).
454
+ Starting in Lighthouse 8.0, Lighthouse relies entirely on native `Intl` support and no longer uses an `Intl` polyfill. If you're using Node 14 or later, there should be no issue because Node is now [built with `full-icu` by default](https://nodejs.medium.com/node-js-12-to-lts-and-node-js-13-is-here-e28d6a4a2bd#9514).
455
455
 
456
- However, if you're using Node 12 (when `small-icu` was the default) or another `small-icu` Node build, you may see Lighthouse log messages about your locale not being available. To remedy this, you can upgrade to Node 14+ or manually install ICU data by using the [`full-icu`](https://www.npmjs.com/package/full-icu) module and the [`--icu-data-dir` node flag](https://nodejs.org/api/intl.html#intl_providing_icu_data_at_runtime) at launch.
456
+ However, if you're using a `small-icu` Node build, you may see Lighthouse log messages about your locale not being available. To remedy this, you can upgrade to Node 14+ or manually install ICU data by using the [`full-icu`](https://www.npmjs.com/package/full-icu) module and the [`--icu-data-dir` node flag](https://nodejs.org/api/intl.html#intl_providing_icu_data_at_runtime) at launch.
457
457
 
458
458
  ### How do I author custom audits to extend Lighthouse?
459
459