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.
- package/cli/test/smokehouse/core-tests.js +2 -0
- package/cli/test/smokehouse/readme.md +1 -1
- package/cli/test/smokehouse/report-assert-test.js +4 -4
- package/cli/test/smokehouse/report-assert.js +1 -1
- package/core/audits/byte-efficiency/legacy-javascript.js +1 -1
- package/core/audits/byte-efficiency/modern-image-formats.js +1 -1
- package/core/audits/byte-efficiency/uses-optimized-images.js +1 -1
- package/core/audits/font-display.js +1 -1
- package/core/audits/redirects.js +3 -3
- package/core/audits/seo/crawlable-anchors.js +1 -1
- package/core/audits/seo/font-size.js +1 -1
- package/core/audits/seo/link-text.js +2 -2
- package/core/audits/service-worker.js +1 -1
- package/core/audits/third-party-summary.js +1 -1
- package/core/audits/valid-source-maps.js +1 -1
- package/core/computed/page-dependency-graph.js +1 -1
- package/core/computed/resource-summary.js +1 -1
- package/core/gather/base-artifacts.js +4 -6
- package/core/gather/gatherers/full-page-screenshot.js +18 -5
- package/core/gather/gatherers/link-elements.js +4 -4
- package/core/gather/gatherers/seo/robots-txt.js +2 -2
- package/core/gather/gatherers/web-app-manifest.js +2 -2
- package/core/gather/navigation-runner.js +2 -4
- package/core/gather/snapshot-runner.js +1 -2
- package/core/gather/timespan-runner.js +2 -6
- package/core/legacy/gather/gather-runner.js +3 -4
- package/core/runner.js +3 -1
- package/core/user-flow.js +2 -2
- package/core/util.cjs +25 -0
- package/dist/report/bundle.esm.js +48 -13
- package/dist/report/flow.js +7 -7
- package/dist/report/standalone.js +8 -8
- package/flow-report/src/summary/category.tsx +3 -3
- package/flow-report/src/summary/summary.tsx +2 -2
- package/package.json +1 -1
- package/report/generator/file-namer.js +2 -2
- package/report/generator/report-generator.js +1 -1
- package/report/renderer/element-screenshot-renderer.js +6 -1
- package/report/renderer/open-tab.js +3 -1
- package/report/renderer/report-renderer.js +3 -3
- package/report/renderer/report-ui-features.js +9 -6
- package/report/renderer/util.js +25 -0
- package/report/test/generator/file-namer-test.js +1 -1
- package/report/test/generator/report-generator-test.js +1 -1
- package/report/test/renderer/report-renderer-test.js +4 -1
- package/report/test/renderer/report-ui-features-test.js +1 -1
- package/types/artifacts.d.ts +2 -8
- package/types/lhr/lhr.d.ts +9 -2
- package/types/lhr/treemap.d.ts +3 -1
- 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
|
-
|
|
161
|
-
}> = ({category, href, gatherMode,
|
|
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={
|
|
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.
|
|
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
|
-
|
|
79
|
+
finalDisplayedUrl={lhr.finalDisplayedUrl}
|
|
80
80
|
/>
|
|
81
81
|
))
|
|
82
82
|
}
|
package/package.json
CHANGED
|
@@ -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 {{
|
|
38
|
+
* @param {{finalDisplayedUrl: string, fetchTime: string}} lhr
|
|
39
39
|
* @return {string}
|
|
40
40
|
*/
|
|
41
41
|
function getLhrFilenamePrefix(lhr) {
|
|
42
|
-
const hostname = new URL(lhr.
|
|
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', '
|
|
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
|
-
|
|
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.
|
|
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.
|
|
86
|
-
metadataUrl.title = report.
|
|
87
|
-
this._dom.safelySetHref(metadataUrl, report.
|
|
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
|
|
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}
|
|
321
|
+
* @param {string} finalDisplayedUrl
|
|
322
322
|
* @return {Array<HTMLElement>}
|
|
323
323
|
*/
|
|
324
|
-
_getThirdPartyRows(rowEls,
|
|
324
|
+
_getThirdPartyRows(rowEls, finalDisplayedUrl) {
|
|
325
325
|
/** @type {Array<HTMLElement>} */
|
|
326
326
|
const thirdPartyRows = [];
|
|
327
|
-
const
|
|
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) !==
|
|
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(
|
|
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 {
|
package/report/renderer/util.js
CHANGED
|
@@ -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
|
-
|
|
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\\",\\"
|
|
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(
|
|
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.
|
|
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,
|
package/types/artifacts.d.ts
CHANGED
|
@@ -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
|
-
|
|
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 {
|
package/types/lhr/lhr.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
19
|
-
|
|
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. */
|
package/types/lhr/treemap.d.ts
CHANGED
package/types/smokehouse.d.ts
CHANGED