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
@@ -155,6 +155,28 @@ describe('util helpers', () => {
155
155
  const preparedResult = Util.prepareReportResult(clonedSampleResult);
156
156
  assert.deepStrictEqual(preparedResult.audits, sampleResult.audits);
157
157
  });
158
+
159
+ it('corrects performance category without hidden group', () => {
160
+ const clonedSampleResult = JSON.parse(JSON.stringify(sampleResult));
161
+
162
+ clonedSampleResult.lighthouseVersion = '8.6.0';
163
+ delete clonedSampleResult.categoryGroups['hidden'];
164
+ for (const auditRef of clonedSampleResult.categories['performance'].auditRefs) {
165
+ if (auditRef.group === 'hidden') {
166
+ delete auditRef.group;
167
+ } else if (!auditRef.group) {
168
+ auditRef.group = 'diagnostics';
169
+ }
170
+ }
171
+ assert.notDeepStrictEqual(clonedSampleResult.categories, sampleResult.categories);
172
+ assert.notDeepStrictEqual(clonedSampleResult.categoryGroups, sampleResult.categoryGroups);
173
+
174
+ // Original audit results should be restored.
175
+ const clonedPreparedResult = Util.prepareReportResult(clonedSampleResult);
176
+ const preparedResult = Util.prepareReportResult(sampleResult);
177
+ assert.deepStrictEqual(clonedPreparedResult.categories, preparedResult.categories);
178
+ assert.deepStrictEqual(clonedPreparedResult.categoryGroups, preparedResult.categoryGroups);
179
+ });
158
180
  });
159
181
 
160
182
  it('appends stack pack descriptions to auditRefs', () => {
@@ -401,10 +423,10 @@ describe('util helpers', () => {
401
423
  const category = {
402
424
  id: 'performance',
403
425
  auditRefs: [
404
- {weight: 3, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'diagnostics'},
405
- {weight: 2, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'diagnostics'},
406
- {weight: 0, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'diagnostics'},
407
- {weight: 1, result: {score: 0, scoreDisplayMode: 'binary'}, group: 'diagnostics'},
426
+ {weight: 3, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'metrics'},
427
+ {weight: 2, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'metrics'},
428
+ {weight: 0, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'metrics'},
429
+ {weight: 1, result: {score: 0, scoreDisplayMode: 'binary'}, group: 'metrics'},
408
430
  ],
409
431
  };
410
432
  const fraction = Util.calculateCategoryFraction(category);
@@ -416,14 +438,14 @@ describe('util helpers', () => {
416
438
  });
417
439
  });
418
440
 
419
- it('ignores manual audits, N/A audits, and performance audits with no group', () => {
441
+ it('ignores manual audits, N/A audits, and hidden audits', () => {
420
442
  const category = {
421
443
  id: 'performance',
422
444
  auditRefs: [
423
- {weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'diagnostics'},
424
- {weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}},
425
- {weight: 1, result: {score: 0, scoreDisplayMode: 'manual'}, group: 'diagnostics'},
426
- {weight: 1, result: {score: 0, scoreDisplayMode: 'notApplicable'}, group: 'diagnostics'},
445
+ {weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'metrics'},
446
+ {weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'hidden'},
447
+ {weight: 1, result: {score: 0, scoreDisplayMode: 'manual'}, group: 'metrics'},
448
+ {weight: 1, result: {score: 0, scoreDisplayMode: 'notApplicable'}, group: 'metrics'},
427
449
  ],
428
450
  };
429
451
  const fraction = Util.calculateCategoryFraction(category);
@@ -435,32 +457,14 @@ describe('util helpers', () => {
435
457
  });
436
458
  });
437
459
 
438
- it('does not ignore audits with no group in non-performance category', () => {
439
- const category = {
440
- id: 'seo',
441
- auditRefs: [
442
- {weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'diagnostics'},
443
- {weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}},
444
- {weight: 1, result: {score: 0, scoreDisplayMode: 'manual'}, group: 'diagnostics'},
445
- ],
446
- };
447
- const fraction = Util.calculateCategoryFraction(category);
448
- expect(fraction).toEqual({
449
- numPassableAudits: 2,
450
- numPassed: 2,
451
- numInformative: 0,
452
- totalWeight: 2,
453
- });
454
- });
455
-
456
460
  it('tracks informative audits separately', () => {
457
461
  const category = {
458
462
  id: 'performance',
459
463
  auditRefs: [
460
- {weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'diagnostics'},
461
- {weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'diagnostics'},
462
- {weight: 0, result: {score: 1, scoreDisplayMode: 'informative'}, group: 'diagnostics'},
463
- {weight: 1, result: {score: 0, scoreDisplayMode: 'informative'}, group: 'diagnostics'},
464
+ {weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'metrics'},
465
+ {weight: 1, result: {score: 1, scoreDisplayMode: 'binary'}, group: 'metrics'},
466
+ {weight: 0, result: {score: 1, scoreDisplayMode: 'informative'}, group: 'metrics'},
467
+ {weight: 1, result: {score: 0, scoreDisplayMode: 'informative'}, group: 'metrics'},
464
468
  ],
465
469
  };
466
470
  const fraction = Util.calculateCategoryFraction(category);
@@ -66,7 +66,6 @@
66
66
  }
67
67
 
68
68
  .tab-panel {
69
- padding: 30px 0;
70
69
  border-top: 1px solid #ccc;
71
70
  }
72
71
 
@@ -92,10 +91,7 @@ body {
92
91
  <body >
93
92
  <noscript>PSI requires JavaScript. Please enable.</noscript>
94
93
 
95
- <div class="element-screenshots-container"></div>
96
-
97
-
98
- <div class="tabset lh-vars lh-root">
94
+ <div class="tabset">
99
95
 
100
96
  <input type="radio" name="tabset" id="tab1" aria-controls="mobile" checked>
101
97
  <label for="tab1">Mobile</label>
@@ -104,13 +100,9 @@ body {
104
100
  <label for="tab2">Desktop</label>
105
101
 
106
102
  <div class="tab-panels">
107
- <section id="mobile" class="tab-panel">
108
- <main></main>
109
- </section>
103
+ <section id="mobile" class="tab-panel"></section>
110
104
 
111
- <section id="desktop" class="tab-panel">
112
- <main></main>
113
- </section>
105
+ <section id="desktop" class="tab-panel"></section>
114
106
 
115
107
  </div>
116
108
  </div>
@@ -5,9 +5,13 @@
5
5
  */
6
6
  'use strict';
7
7
 
8
- /** @fileoverview This file is a glorified call of prepareLabData. */
8
+ /** @fileoverview This file exercises two LH reports within the same DOM. */
9
9
 
10
- /** @typedef {import('../clients/psi.js').PrepareLabDataResult} PrepareLabDataResult */
10
+ /** @typedef {import('../clients/bundle.js')} lighthouseRenderer */
11
+
12
+ /** @type {lighthouseRenderer} */
13
+ // @ts-expect-error
14
+ const lighthouseRenderer = window['report'];
11
15
 
12
16
  (async function __initPsiReports__() {
13
17
  // @ts-expect-error
@@ -22,22 +26,23 @@
22
26
  for (const [tabId, lhr] of Object.entries(lhrs)) {
23
27
  await distinguishLHR(lhr, tabId);
24
28
 
25
- // @ts-expect-error
26
- const pldd = /** @type {PrepareLabDataResult} */ (window.prepareLabData(lhr, document));
27
- const {scoreGaugeEl, perfCategoryEl,
28
- finalScreenshotDataUri, scoreScaleEl, installFeatures} = pldd;
29
-
30
- const container = document.querySelector(`#${tabId} main`);
29
+ const container = document.querySelector(`section#${tabId}`);
31
30
  if (!container) throw new Error('Unexpected DOM. Bailing.');
32
- container.append(scoreGaugeEl);
33
- container.append(scoreScaleEl);
34
- if (finalScreenshotDataUri) {
35
- const imgEl = document.createElement('img');
36
- imgEl.src = finalScreenshotDataUri;
37
- container.append(imgEl);
31
+
32
+ try {
33
+ const reportRootEl = lighthouseRenderer.renderReport(lhr, {
34
+ omitTopbar: true,
35
+ disableAutoDarkModeAndFireworks: true,
36
+ });
37
+ // TODO: display warnings if appropriate.
38
+ for (const el of reportRootEl.querySelectorAll('.lh-warnings')) {
39
+ el.setAttribute('hidden', 'true');
40
+ }
41
+ container.append(reportRootEl);
42
+ } catch (e) {
43
+ console.error(e);
44
+ container.textContent = 'Error: LHR failed to render.';
38
45
  }
39
- container.append(perfCategoryEl);
40
- installFeatures(container);
41
46
  }
42
47
  })();
43
48
 
@@ -49,7 +54,6 @@
49
54
  * @param {string} tabId
50
55
  */
51
56
  async function distinguishLHR(lhr, tabId) {
52
- lhr.categories.performance.title += ` ${tabId}`; // for easier identification
53
57
  if (tabId === 'desktop') {
54
58
  lhr.categories.performance.score = 0.81;
55
59
  }
@@ -78,15 +82,15 @@ async function decorateScreenshot(datauri, tabId) {
78
82
  img.src = datauri;
79
83
  });
80
84
  const c = document.createElement('canvas');
81
- c.width = img.width;
82
- c.height = img.height;
85
+ c.width = tabId === 'desktop' ? 280 : img.width;
86
+ c.height = tabId === 'desktop' ? 194 : img.height;
83
87
 
84
88
  const ctx = c.getContext('2d');
85
89
  if (!ctx) throw new Error();
86
- ctx.drawImage(img, 0, 0);
87
- ctx.font = `${img.width / 2}px serif`;
90
+ ctx.drawImage(img, 0, 0, c.width, c.height);
91
+ ctx.font = `${c.width / 2}px serif`;
88
92
  ctx.textAlign = 'center';
89
93
  ctx.globalAlpha = 0.7;
90
- ctx.fillText(tabId === 'mobile' ? '📱' : '💻', img.width / 2, Math.min(img.height / 2, 700));
94
+ ctx.fillText(tabId === 'mobile' ? '📱' : '💻', c.width / 2, Math.min(c.height / 2, 700));
91
95
  return c.toDataURL();
92
96
  }
@@ -8,6 +8,7 @@ import AuditDetails from '../../types/lhr/audit-details';
8
8
  import {FormattedIcu as FormattedIcu_, IcuMessage as IcuMessage_} from '../../types/lhr/i18n';
9
9
  import LHResult from '../../types/lhr/lhr';
10
10
  import ReportResult_ from './report-result';
11
+ import Renderer_ from './report-renderer';
11
12
  import * as Settings from '../../types/lhr/settings';
12
13
  import Treemap_ from '../../types/lhr/treemap';
13
14
 
@@ -16,6 +17,7 @@ declare global {
16
17
  module LH {
17
18
  export import Result = LHResult;
18
19
  export import ReportResult = ReportResult_;
20
+ export import Renderer = Renderer_;
19
21
  export import Locale = Settings.Locale;
20
22
  export type IcuMessage = IcuMessage_;
21
23
  export type FormattedIcu<T> = FormattedIcu_<T>;
@@ -0,0 +1,23 @@
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
+
7
+ import { Result as AuditResult } from "../../types/lhr/audit-result";
8
+
9
+ declare module Renderer {
10
+ function renderReport(lhr: AuditResult, options?: Options): HTMLElement;
11
+
12
+ interface Options {
13
+ /**
14
+ * Don't automatically apply dark-mode to dark based on (prefers-color-scheme: dark). (DevTools and PSI don't want this.)
15
+ * Also, the fireworks easter-egg will want to flip to dark, so this setting will also disable chance of fireworks. */
16
+ disableAutoDarkModeAndFireworks?: boolean;
17
+
18
+ /** Disable the topbar UI component */
19
+ omitTopbar?: boolean;
20
+ }
21
+ }
22
+
23
+ export default Renderer;
@@ -7,26 +7,26 @@
7
7
 
8
8
  const fs = require('fs');
9
9
 
10
- const MessageFormat = require('intl-messageformat').default;
10
+ const MessageFormat = require('intl-messageformat');
11
11
  const {isObjectOfUnknownValues, isObjectOrArrayOfUnknownValues} = require('../type-verifiers.js');
12
12
 
13
13
  /** Contains available locales with messages. May be an empty object if bundled. */
14
- const LOCALE_MESSAGES = require('./locales.js');
14
+ /** @type {import('./locales')} */
15
+ // @ts-expect-error TODO(esmodules): remove when file is es modules.
16
+ const LOCALE_MESSAGES = require('./locales.js').default || require('./locales.js');
17
+
18
+ const DEFAULT_LOCALE = 'en-US';
15
19
 
16
20
  /**
17
21
  * The locale tags for the localized messages available to Lighthouse on disk.
18
- * When bundled, these will be inlined by brfs.
22
+ * When bundled, these will be inlined by `inline-fs`.
19
23
  * These locales are considered the "canonical" locales. We support other locales which
20
24
  * are simply aliases to one of these. ex: es-AR (alias) -> es-419 (canonical)
21
25
  */
22
- let CANONICAL_LOCALES = ['__availableLocales__'];
23
- // TODO: need brfs in gh-pages-app. For now, above is replaced, see build-i18n.module.js
24
- if (fs.readdirSync) {
25
- CANONICAL_LOCALES = fs.readdirSync(__dirname + '/locales/')
26
- .filter(basename => basename.endsWith('.json') && !basename.endsWith('.ctc.json'))
27
- .map(locale => locale.replace('.json', ''))
28
- .sort();
29
- }
26
+ const CANONICAL_LOCALES = fs.readdirSync(__dirname + '/locales/')
27
+ .filter(basename => basename.endsWith('.json') && !basename.endsWith('.ctc.json'))
28
+ .map(locale => locale.replace('.json', ''))
29
+ .sort();
30
30
 
31
31
  /** @typedef {import('intl-messageformat-parser').Element} MessageElement */
32
32
  /** @typedef {import('intl-messageformat-parser').ArgumentElement} ArgumentElement */
@@ -95,7 +95,7 @@ function collectAllCustomElementsFromICU(icuElements, seenElementsById = new Map
95
95
  * Returns a copy of the `values` object, with the values formatted based on how
96
96
  * they will be used in their icuMessage, e.g. KB or milliseconds. The original
97
97
  * object is unchanged.
98
- * @param {MessageFormat} messageFormatter
98
+ * @param {MessageFormat.IntlMessageFormat} messageFormatter
99
99
  * @param {Readonly<Record<string, string | number>>} values
100
100
  * @param {string} lhlMessage Used for clear error logging.
101
101
  * @return {Record<string, string | number>}
@@ -169,11 +169,14 @@ function _preformatValues(messageFormatter, values, lhlMessage) {
169
169
  * @param {LH.Locale} locale
170
170
  * @return {string}
171
171
  */
172
- function _formatMessage(message, values = {}, locale) {
172
+ function formatMessage(message, values = {}, locale) {
173
173
  // When using accented english, force the use of a different locale for number formatting.
174
174
  const localeForMessageFormat = (locale === 'en-XA' || locale === 'en-XL') ? 'de-DE' : locale;
175
175
 
176
- const formatter = new MessageFormat(message, localeForMessageFormat, formats);
176
+ // This package is not correctly bundled by Rollup.
177
+ /** @type {typeof MessageFormat.IntlMessageFormat} */
178
+ const MessageFormatCtor = MessageFormat.IntlMessageFormat || MessageFormat;
179
+ const formatter = new MessageFormatCtor(message, localeForMessageFormat, formats);
177
180
 
178
181
  // Preformat values for the message format like KB and milliseconds.
179
182
  const valuesForMessageFormat = _preformatValues(formatter, values, message);
@@ -189,19 +192,21 @@ function _formatMessage(message, values = {}, locale) {
189
192
  * @return {string}
190
193
  */
191
194
  function _localizeIcuMessage(icuMessage, locale) {
192
- const localeMessages = LOCALE_MESSAGES[locale];
193
- if (!localeMessages) throw new Error(`Unsupported locale '${locale}'`);
195
+ const localeMessages = _getLocaleMessages(locale);
194
196
  const localeMessage = localeMessages[icuMessage.i18nId];
195
197
 
196
- // Fall back to the default (usually the original english message) if we couldn't find a
197
- // message in the specified locale. This could be because of string drift between
198
- // Lighthouse versions or because new strings haven't been updated yet. Better to have
199
- // an english message than no message at all; in some cases it won't even matter.
198
+ // Use the DEFAULT_LOCALE fallback (usually the original english message) if we couldn't
199
+ // find a message in the specified locale. Possible reasons:
200
+ // - string drift between Lighthouse versions
201
+ // - in a bundle stripped of locale files but running in the DEFAULT_LOCALE
202
+ // - new strings haven't been updated yet in a local dev run
203
+ // Better to have an english message than no message at all; in some cases it
204
+ // won't even matter.
200
205
  if (!localeMessage) {
201
206
  return icuMessage.formattedDefault;
202
207
  }
203
208
 
204
- return _formatMessage(localeMessage.message, icuMessage.values, locale);
209
+ return formatMessage(localeMessage.message, icuMessage.values, locale);
205
210
  }
206
211
 
207
212
  /**
@@ -209,9 +214,10 @@ function _localizeIcuMessage(icuMessage, locale) {
209
214
  * @return {Record<string, string>}
210
215
  */
211
216
  function getRendererFormattedStrings(locale) {
212
- const localeMessages = LOCALE_MESSAGES[locale];
213
- if (!localeMessages) throw new Error(`Unsupported locale '${locale}'`);
217
+ const localeMessages = _getLocaleMessages(locale);
214
218
 
219
+ // If `localeMessages` is empty in the bundled and DEFAULT_LOCALE case, this
220
+ // will be empty and the report will fall back to the util UIStrings for these.
215
221
  const icuMessageIds = Object.keys(localeMessages).filter(f => f.startsWith('report/'));
216
222
  /** @type {Record<string, string>} */
217
223
  const strings = {};
@@ -349,12 +355,38 @@ function replaceIcuMessages(inputObject, locale) {
349
355
  return icuMessagePaths;
350
356
  }
351
357
 
358
+ /**
359
+ * Returns the locale messages for the given `locale`, if they exist.
360
+ * Throws if an unsupported locale.
361
+ *
362
+ * NOTE: If DEFAULT_LOCALE is requested and this is inside a bundle with locale
363
+ * messages stripped, an empty object will be returned. Default fallbacks will need to handle that case.
364
+ * @param {LH.Locale} locale
365
+ * @return {import('./locales').LhlMessages}
366
+ */
367
+ function _getLocaleMessages(locale) {
368
+ const localeMessages = LOCALE_MESSAGES[locale];
369
+ if (!localeMessages) {
370
+ if (locale === DEFAULT_LOCALE) {
371
+ // If the default locale isn't in LOCALE_MESSAGES, this is likely executing
372
+ // in a bundle. Let the caller use the fallbacks available.
373
+ return {};
374
+ }
375
+ throw new Error(`Unsupported locale '${locale}'`);
376
+ }
377
+
378
+ return localeMessages;
379
+ }
380
+
352
381
  /**
353
382
  * Returns whether the `requestedLocale` can be used.
354
383
  * @param {LH.Locale} requestedLocale
355
384
  * @return {boolean}
356
385
  */
357
386
  function hasLocale(requestedLocale) {
387
+ // The default locale is always supported through `IcuMessage.formattedDefault`.
388
+ if (requestedLocale === DEFAULT_LOCALE) return true;
389
+
358
390
  const hasIntlSupport = Intl.NumberFormat.supportedLocalesOf([requestedLocale]).length > 0;
359
391
  const hasMessages = Boolean(LOCALE_MESSAGES[requestedLocale]);
360
392
 
@@ -362,8 +394,9 @@ function hasLocale(requestedLocale) {
362
394
  }
363
395
 
364
396
  /**
365
- * Returns a list of canonical locales (each of which may have aliases, but those would
366
- * only show in getAvailableLocales)
397
+ * Returns a list of canonical locales, as defined by the existent message files.
398
+ * In practice, each of these may have aliases in the full list returned by
399
+ * `getAvailableLocales()`.
367
400
  * TODO: create a CanonicalLocale type
368
401
  * @return {Array<string>}
369
402
  */
@@ -375,13 +408,13 @@ function getCanonicalLocales() {
375
408
  * Returns a list of available locales.
376
409
  * - if full build, this includes all canonical locales, aliases, and any locale added
377
410
  * via `registerLocaleData`.
378
- * - if bundled and locale messages have been stripped (locales.js shimmed), this includes no
379
- * locales (perhaps available in a separate bundle), and perhaps any locales
380
- * from `registerLocaleData`.
411
+ * - if bundled and locale messages have been stripped (locales.js shimmed), this includes
412
+ * only DEFAULT_LOCALE and any locales from `registerLocaleData`.
381
413
  * @return {Array<LH.Locale>}
382
414
  */
383
415
  function getAvailableLocales() {
384
- return /** @type {Array<LH.Locale>} */ (Object.keys(LOCALE_MESSAGES).sort());
416
+ const localesWithMessages = new Set([...Object.keys(LOCALE_MESSAGES), DEFAULT_LOCALE]);
417
+ return /** @type {Array<LH.Locale>} */ ([...localesWithMessages].sort());
385
418
  }
386
419
 
387
420
  /**
@@ -407,6 +440,7 @@ function getIcuMessageIdParts(i18nMessageId) {
407
440
  }
408
441
 
409
442
  module.exports = {
443
+ DEFAULT_LOCALE,
410
444
  _formatPathAsString,
411
445
  collectAllCustomElementsFromICU,
412
446
  isIcuMessage,
@@ -415,7 +449,7 @@ module.exports = {
415
449
  replaceIcuMessages,
416
450
  hasLocale,
417
451
  registerLocaleData,
418
- _formatMessage,
452
+ formatMessage,
419
453
  getIcuMessageIdParts,
420
454
  getAvailableLocales,
421
455
  getCanonicalLocales,