lighthouse 9.5.0-dev.20221003 → 9.5.0-dev.20221004

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 (50) hide show
  1. package/cli/test/smokehouse/core-tests.js +2 -0
  2. package/cli/test/smokehouse/readme.md +1 -1
  3. package/cli/test/smokehouse/report-assert-test.js +4 -4
  4. package/cli/test/smokehouse/report-assert.js +1 -1
  5. package/core/audits/byte-efficiency/legacy-javascript.js +1 -1
  6. package/core/audits/byte-efficiency/modern-image-formats.js +1 -1
  7. package/core/audits/byte-efficiency/uses-optimized-images.js +1 -1
  8. package/core/audits/font-display.js +1 -1
  9. package/core/audits/redirects.js +3 -3
  10. package/core/audits/seo/crawlable-anchors.js +1 -1
  11. package/core/audits/seo/font-size.js +1 -1
  12. package/core/audits/seo/link-text.js +2 -2
  13. package/core/audits/service-worker.js +1 -1
  14. package/core/audits/third-party-summary.js +1 -1
  15. package/core/audits/valid-source-maps.js +1 -1
  16. package/core/computed/page-dependency-graph.js +1 -1
  17. package/core/computed/resource-summary.js +1 -1
  18. package/core/gather/base-artifacts.js +4 -6
  19. package/core/gather/gatherers/full-page-screenshot.js +18 -5
  20. package/core/gather/gatherers/link-elements.js +4 -4
  21. package/core/gather/gatherers/seo/robots-txt.js +2 -2
  22. package/core/gather/gatherers/web-app-manifest.js +2 -2
  23. package/core/gather/navigation-runner.js +2 -4
  24. package/core/gather/snapshot-runner.js +1 -2
  25. package/core/gather/timespan-runner.js +2 -6
  26. package/core/legacy/gather/gather-runner.js +3 -4
  27. package/core/runner.js +3 -1
  28. package/core/user-flow.js +2 -2
  29. package/core/util.cjs +25 -0
  30. package/dist/report/bundle.esm.js +48 -13
  31. package/dist/report/flow.js +7 -7
  32. package/dist/report/standalone.js +8 -8
  33. package/flow-report/src/summary/category.tsx +3 -3
  34. package/flow-report/src/summary/summary.tsx +2 -2
  35. package/package.json +1 -1
  36. package/report/generator/file-namer.js +2 -2
  37. package/report/generator/report-generator.js +1 -1
  38. package/report/renderer/element-screenshot-renderer.js +6 -1
  39. package/report/renderer/open-tab.js +3 -1
  40. package/report/renderer/report-renderer.js +3 -3
  41. package/report/renderer/report-ui-features.js +9 -6
  42. package/report/renderer/util.js +25 -0
  43. package/report/test/generator/file-namer-test.js +1 -1
  44. package/report/test/generator/report-generator-test.js +1 -1
  45. package/report/test/renderer/report-renderer-test.js +4 -1
  46. package/report/test/renderer/report-ui-features-test.js +1 -1
  47. package/types/artifacts.d.ts +2 -8
  48. package/types/lhr/lhr.d.ts +9 -2
  49. package/types/lhr/treemap.d.ts +3 -1
  50. package/types/smokehouse.d.ts +1 -1
@@ -157,8 +157,8 @@ const SummaryCategory: FunctionComponent<{
157
157
  category: LH.ReportResult.Category|undefined,
158
158
  href: string,
159
159
  gatherMode: LH.Result.GatherMode,
160
- finalUrl: string,
161
- }> = ({category, href, gatherMode, finalUrl}) => {
160
+ finalDisplayedUrl: string,
161
+ }> = ({category, href, gatherMode, finalDisplayedUrl}) => {
162
162
  return (
163
163
  <div className="SummaryCategory">
164
164
  {
@@ -169,7 +169,7 @@ const SummaryCategory: FunctionComponent<{
169
169
  href={href}
170
170
  gatherMode={gatherMode}
171
171
  />
172
- <SummaryTooltip category={category} gatherMode={gatherMode} url={finalUrl}/>
172
+ <SummaryTooltip category={category} gatherMode={gatherMode} url={finalDisplayedUrl}/>
173
173
  </div> :
174
174
  <div className="SummaryCategory__null" data-testid="SummaryCategory__null"/>
175
175
  }
@@ -23,7 +23,7 @@ const SummaryNavigationHeader: FunctionComponent<{lhr: LH.Result}> = ({lhr}) =>
23
23
  <div className="SummaryNavigationHeader" data-testid="SummaryNavigationHeader">
24
24
  <FlowSegment/>
25
25
  <div className="SummaryNavigationHeader__url">
26
- <a rel="noopener" target="_blank" href={lhr.finalUrl}>{lhr.finalUrl}</a>
26
+ <a rel="noopener" target="_blank" href={lhr.finalDisplayedUrl}>{lhr.finalDisplayedUrl}</a>
27
27
  </div>
28
28
  <div className="SummaryNavigationHeader__category">
29
29
  {strings.categoryPerformance}
@@ -76,7 +76,7 @@ const SummaryFlowStep: FunctionComponent<{
76
76
  category={reportResult.categories[c]}
77
77
  href={`#index=${hashIndex}&anchor=${c}`}
78
78
  gatherMode={lhr.gatherMode}
79
- finalUrl={lhr.finalUrl}
79
+ finalDisplayedUrl={lhr.finalDisplayedUrl}
80
80
  />
81
81
  ))
82
82
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lighthouse",
3
3
  "type": "module",
4
- "version": "9.5.0-dev.20221003",
4
+ "version": "9.5.0-dev.20221004",
5
5
  "description": "Automated auditing, performance metrics, and best practices for the web.",
6
6
  "main": "./core/index.js",
7
7
  "bin": {
@@ -35,11 +35,11 @@ function getFilenamePrefix(name, fetchTime) {
35
35
 
36
36
  /**
37
37
  * Generate a filenamePrefix of hostname_YYYY-MM-DD_HH-MM-SS.
38
- * @param {{finalUrl: string, fetchTime: string}} lhr
38
+ * @param {{finalDisplayedUrl: string, fetchTime: string}} lhr
39
39
  * @return {string}
40
40
  */
41
41
  function getLhrFilenamePrefix(lhr) {
42
- const hostname = new URL(lhr.finalUrl).hostname;
42
+ const hostname = new URL(lhr.finalDisplayedUrl).hostname;
43
43
  return getFilenamePrefix(hostname, lhr.fetchTime);
44
44
  }
45
45
 
@@ -101,7 +101,7 @@ class ReportGenerator {
101
101
 
102
102
  const rows = [];
103
103
  const topLevelKeys = /** @type {const} */(
104
- ['requestedUrl', 'finalUrl', 'fetchTime', 'gatherMode']);
104
+ ['requestedUrl', 'finalDisplayedUrl', 'fetchTime', 'gatherMode']);
105
105
 
106
106
  // First we have metadata about the LHR.
107
107
  rows.push(rowFormatter(topLevelKeys));
@@ -239,7 +239,12 @@ export class ElementScreenshotRenderer {
239
239
  width: maxRenderSizeDC.width / zoomFactor,
240
240
  height: maxRenderSizeDC.height / zoomFactor,
241
241
  };
242
- elementPreviewSizeSC.width = Math.min(screenshot.width, elementPreviewSizeSC.width);
242
+
243
+ if (screenshot.width < elementPreviewSizeSC.width) {
244
+ elementPreviewSizeSC.width = screenshot.width;
245
+ elementPreviewSizeSC.height = screenshot.height;
246
+ }
247
+
243
248
  /* This preview size is either the size of the thumbnail or size of the Lightbox */
244
249
  const elementPreviewSizeDC = {
245
250
  width: elementPreviewSizeSC.width * zoomFactor,
@@ -37,7 +37,7 @@ function computeWindowNameSuffix(json) {
37
37
  // @ts-expect-error - If this is a v2 LHR, use old `generatedTime`.
38
38
  const fallbackFetchTime = /** @type {string} */ (json.generatedTime);
39
39
  const fetchTime = json.fetchTime || fallbackFetchTime;
40
- return `${json.lighthouseVersion}-${json.finalUrl}-${fetchTime}`;
40
+ return `${json.lighthouseVersion}-${json.finalDisplayedUrl}-${fetchTime}`;
41
41
  }
42
42
 
43
43
  /**
@@ -119,7 +119,9 @@ function openTreemap(json) {
119
119
  /** @type {LH.Treemap.Options} */
120
120
  const treemapOptions = {
121
121
  lhr: {
122
+ mainDocumentUrl: json.mainDocumentUrl,
122
123
  finalUrl: json.finalUrl,
124
+ finalDisplayedUrl: json.finalDisplayedUrl,
123
125
  audits: {
124
126
  'script-treemap-data': json.audits['script-treemap-data'],
125
127
  },
@@ -82,9 +82,9 @@ export class ReportRenderer {
82
82
  _renderReportTopbar(report) {
83
83
  const el = this._dom.createComponent('topbar');
84
84
  const metadataUrl = this._dom.find('a.lh-topbar__url', el);
85
- metadataUrl.textContent = report.finalUrl;
86
- metadataUrl.title = report.finalUrl;
87
- this._dom.safelySetHref(metadataUrl, report.finalUrl);
85
+ metadataUrl.textContent = report.finalDisplayedUrl;
86
+ metadataUrl.title = report.finalDisplayedUrl;
87
+ this._dom.safelySetHref(metadataUrl, report.finalDisplayedUrl);
88
88
  return el;
89
89
  }
90
90
 
@@ -242,7 +242,7 @@ export class ReportUIFeatures {
242
242
 
243
243
  tablesWithUrls.forEach((tableEl) => {
244
244
  const rowEls = getTableRows(tableEl);
245
- const thirdPartyRows = this._getThirdPartyRows(rowEls, this.json.finalUrl);
245
+ const thirdPartyRows = this._getThirdPartyRows(rowEls, Util.getFinalDisplayedUrl(this.json));
246
246
 
247
247
  // create input box
248
248
  const filterTemplate = this._dom.createComponent('3pFilter');
@@ -318,13 +318,13 @@ export class ReportUIFeatures {
318
318
  * From a table with URL entries, finds the rows containing third-party URLs
319
319
  * and returns them.
320
320
  * @param {HTMLElement[]} rowEls
321
- * @param {string} finalUrl
321
+ * @param {string} finalDisplayedUrl
322
322
  * @return {Array<HTMLElement>}
323
323
  */
324
- _getThirdPartyRows(rowEls, finalUrl) {
324
+ _getThirdPartyRows(rowEls, finalDisplayedUrl) {
325
325
  /** @type {Array<HTMLElement>} */
326
326
  const thirdPartyRows = [];
327
- const finalUrlRootDomain = Util.getRootDomain(finalUrl);
327
+ const finalDisplayedUrlRootDomain = Util.getRootDomain(finalDisplayedUrl);
328
328
 
329
329
  for (const rowEl of rowEls) {
330
330
  if (rowEl.classList.contains('lh-sub-item-row')) continue;
@@ -334,7 +334,7 @@ export class ReportUIFeatures {
334
334
 
335
335
  const datasetUrl = urlItem.dataset.url;
336
336
  if (!datasetUrl) continue;
337
- const isThirdParty = Util.getRootDomain(datasetUrl) !== finalUrlRootDomain;
337
+ const isThirdParty = Util.getRootDomain(datasetUrl) !== finalDisplayedUrlRootDomain;
338
338
  if (!isThirdParty) continue;
339
339
 
340
340
  thirdPartyRows.push(rowEl);
@@ -348,7 +348,10 @@ export class ReportUIFeatures {
348
348
  */
349
349
  _saveFile(blob) {
350
350
  const ext = blob.type.match('json') ? '.json' : '.html';
351
- const filename = getLhrFilenamePrefix(this.json) + ext;
351
+ const filename = getLhrFilenamePrefix({
352
+ finalDisplayedUrl: Util.getFinalDisplayedUrl(this.json),
353
+ fetchTime: this.json.fetchTime,
354
+ }) + ext;
352
355
  if (this._opts.onSaveFileOverride) {
353
356
  this._opts.onSaveFileOverride(blob, filename);
354
357
  } else {
@@ -50,6 +50,28 @@ class Util {
50
50
  return `%10d${NBSP}ms`;
51
51
  }
52
52
 
53
+ /**
54
+ * If LHR is older than 10.0 it will not have the `finalDisplayedUrl` property.
55
+ * Old LHRs should have the `finalUrl` property which will work fine for the report.
56
+ *
57
+ * @param {LH.Result} lhr
58
+ */
59
+ static getFinalDisplayedUrl(lhr) {
60
+ if (lhr.finalDisplayedUrl) return lhr.finalDisplayedUrl;
61
+ if (lhr.finalUrl) return lhr.finalUrl;
62
+ throw new Error('Could not determine final displayed URL');
63
+ }
64
+
65
+ /**
66
+ * If LHR is older than 10.0 it will not have the `mainDocumentUrl` property.
67
+ * Old LHRs should have the `finalUrl` property which is the same as `mainDocumentUrl`.
68
+ *
69
+ * @param {LH.Result} lhr
70
+ */
71
+ static getMainDocumentUrl(lhr) {
72
+ return lhr.mainDocumentUrl || lhr.finalUrl;
73
+ }
74
+
53
75
  /**
54
76
  * Returns a new LHR that's reshaped for slightly better ergonomics within the report rendereer.
55
77
  * Also, sets up the localized UI strings used within renderer and makes changes to old LHRs to be
@@ -72,6 +94,9 @@ class Util {
72
94
  clone.configSettings.formFactor = clone.configSettings.emulatedFormFactor;
73
95
  }
74
96
 
97
+ clone.finalDisplayedUrl = this.getFinalDisplayedUrl(clone);
98
+ clone.mainDocumentUrl = this.getMainDocumentUrl(clone);
99
+
75
100
  for (const audit of Object.values(clone.audits)) {
76
101
  // Turn 'not-applicable' (LHR <4.0) and 'not_applicable' (older proto versions)
77
102
  // into 'notApplicable' (LHR ≥4.0).
@@ -12,7 +12,7 @@ import {getLhrFilenamePrefix} from '../../generator/file-namer.js';
12
12
  describe('file-namer helper', () => {
13
13
  it('generates filename prefixes', () => {
14
14
  const results = {
15
- finalUrl: 'https://testexample.com',
15
+ finalDisplayedUrl: 'https://testexample.com',
16
16
  fetchTime: '2017-01-06T02:34:56.217Z',
17
17
  };
18
18
  const str = getLhrFilenamePrefix(results);
@@ -90,7 +90,7 @@ describe('ReportGenerator', () => {
90
90
  const lines = csvOutput.split('\n');
91
91
  expect(lines.length).toBeGreaterThan(100);
92
92
  expect(lines.slice(0, 15).join('\n')).toMatchInlineSnapshot(`
93
- "\\"requestedUrl\\",\\"finalUrl\\",\\"fetchTime\\",\\"gatherMode\\"
93
+ "\\"requestedUrl\\",\\"finalDisplayedUrl\\",\\"fetchTime\\",\\"gatherMode\\"
94
94
  \\"http://localhost:10200/dobetterweb/dbw_tester.html\\",\\"http://localhost:10200/dobetterweb/dbw_tester.html\\",\\"2021-09-07T20:11:11.853Z\\",\\"navigation\\"
95
95
 
96
96
  category,score
@@ -71,7 +71,10 @@ describe('ReportRenderer', () => {
71
71
 
72
72
  it('renders a topbar', () => {
73
73
  const topbar = renderer._renderReportTopbar(sampleResults);
74
- assert.equal(topbar.querySelector('.lh-topbar__url').textContent, sampleResults.finalUrl);
74
+ assert.equal(
75
+ topbar.querySelector('.lh-topbar__url').textContent,
76
+ sampleResults.finalDisplayedUrl
77
+ );
75
78
  });
76
79
 
77
80
  it('renders a header', () => {
@@ -107,7 +107,7 @@ describe('ReportUIFeatures', () => {
107
107
 
108
108
  before(() => {
109
109
  const lhr = JSON.parse(JSON.stringify(sampleResults));
110
- lhr.requestedUrl = lhr.finalUrl = 'http://www.example.com';
110
+ lhr.requestedUrl = lhr.finalDisplayedUrl = 'http://www.example.com';
111
111
  const webpAuditItemTemplate = {
112
112
  ...sampleResults.audits['modern-image-formats'].details.items[0],
113
113
  wastedBytes: 8.8 * 1024,
@@ -188,8 +188,6 @@ declare module Artifacts {
188
188
  type MetaElement = Artifacts['MetaElements'][0];
189
189
 
190
190
  interface URL {
191
- /** URL of the main frame before Lighthouse starts. */
192
- initialUrl: string;
193
191
  /**
194
192
  * URL of the initially requested URL during a Lighthouse navigation.
195
193
  * Will be `undefined` in timespan/snapshot.
@@ -200,12 +198,8 @@ declare module Artifacts {
200
198
  * Will be `undefined` in timespan/snapshot.
201
199
  */
202
200
  mainDocumentUrl?: string;
203
- /**
204
- * Will be the same as `mainDocumentUrl` in navigation mode.
205
- * Wil be the URL of the main frame after Lighthouse finishes in timespan/snapshot.
206
- * TODO: Use the main frame URL in navigation mode as well.
207
- */
208
- finalUrl: string;
201
+ /** URL displayed on the page after Lighthouse finishes. */
202
+ finalDisplayedUrl: string;
209
203
  }
210
204
 
211
205
  interface NodeDetails {
@@ -15,8 +15,15 @@ interface Result {
15
15
  gatherMode: Result.GatherMode;
16
16
  /** The URL that Lighthouse initially navigated to. Will be `undefined` in timespan/snapshot. */
17
17
  requestedUrl?: string;
18
- /** The post-redirects URL that Lighthouse loaded. */
19
- finalUrl: string;
18
+ /** URL of the last document request during a Lighthouse navigation. Will be `undefined` in timespan/snapshot. */
19
+ mainDocumentUrl?: string;
20
+ /**
21
+ * For historical reasons, this will always be the same as `mainDocumentUrl`.
22
+ * @deprecated
23
+ */
24
+ finalUrl?: string;
25
+ /** The URL displayed on the page after Lighthouse finishes. */
26
+ finalDisplayedUrl: string;
20
27
  /** The ISO-8601 timestamp of when the results were generated. */
21
28
  fetchTime: string;
22
29
  /** The version of Lighthouse with which these results were generated. */
@@ -10,7 +10,9 @@ import {Locale} from './settings';
10
10
  declare module Treemap {
11
11
  interface Options {
12
12
  lhr: {
13
- finalUrl: string;
13
+ mainDocumentUrl?: string;
14
+ finalUrl?: string;
15
+ finalDisplayedUrl: string;
14
16
  audits: {
15
17
  'script-treemap-data': AuditResult;
16
18
  };
@@ -13,7 +13,7 @@ declare global {
13
13
  interface ExpectedLHR {
14
14
  audits: Record<string, any>;
15
15
  requestedUrl: string;
16
- finalUrl: string | RegExp;
16
+ finalDisplayedUrl: string | RegExp;
17
17
  userAgent?: string | RegExp;
18
18
  runWarnings?: any;
19
19
  runtimeError?: {