lighthouse 9.5.0-dev.20220329 → 9.5.0-dev.20220330
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/dist/report/bundle.esm.js +20 -18
- package/dist/report/flow.js +1 -1
- package/dist/report/standalone.js +1 -1
- package/lighthouse-cli/test/smokehouse/lighthouse-runners/devtools.js +26 -18
- package/lighthouse-core/audits/byte-efficiency/byte-efficiency-audit.js +2 -1
- package/lighthouse-core/audits/byte-efficiency/efficient-animated-content.js +1 -1
- package/lighthouse-core/audits/byte-efficiency/offscreen-images.js +3 -2
- package/lighthouse-core/audits/byte-efficiency/render-blocking-resources.js +1 -1
- package/lighthouse-core/audits/byte-efficiency/unused-javascript.js +1 -1
- package/lighthouse-core/audits/byte-efficiency/uses-responsive-images.js +1 -1
- package/lighthouse-core/audits/byte-efficiency/uses-text-compression.js +1 -1
- package/lighthouse-core/audits/dobetterweb/uses-http2.js +2 -1
- package/lighthouse-core/audits/long-tasks.js +3 -2
- package/lighthouse-core/audits/metrics/first-contentful-paint-3g.js +2 -2
- package/lighthouse-core/audits/metrics/first-contentful-paint.js +3 -2
- package/lighthouse-core/audits/metrics/first-meaningful-paint.js +3 -2
- package/lighthouse-core/audits/metrics/interactive.js +3 -2
- package/lighthouse-core/audits/metrics/largest-contentful-paint.js +3 -2
- package/lighthouse-core/audits/metrics/max-potential-fid.js +3 -2
- package/lighthouse-core/audits/metrics/speed-index.js +3 -2
- package/lighthouse-core/audits/metrics/total-blocking-time.js +3 -2
- package/lighthouse-core/audits/metrics.js +3 -2
- package/lighthouse-core/audits/predictive-perf.js +2 -1
- package/lighthouse-core/audits/preload-lcp-image.js +1 -1
- package/lighthouse-core/audits/redirects.js +1 -1
- package/lighthouse-core/audits/timing-budget.js +3 -2
- package/lighthouse-core/audits/uses-rel-preconnect.js +1 -1
- package/lighthouse-core/audits/uses-rel-preload.js +1 -1
- package/lighthouse-core/computed/critical-request-chains.js +2 -9
- package/lighthouse-core/computed/main-resource.js +1 -1
- package/lighthouse-core/computed/metrics/first-contentful-paint-all-frames.js +1 -1
- package/lighthouse-core/computed/metrics/first-contentful-paint.js +1 -1
- package/lighthouse-core/computed/metrics/first-meaningful-paint.js +1 -1
- package/lighthouse-core/computed/metrics/interactive.js +1 -1
- package/lighthouse-core/computed/metrics/lantern-first-contentful-paint.js +1 -1
- package/lighthouse-core/computed/metrics/lantern-first-meaningful-paint.js +1 -1
- package/lighthouse-core/computed/metrics/lantern-interactive.js +1 -1
- package/lighthouse-core/computed/metrics/lantern-largest-contentful-paint.js +1 -1
- package/lighthouse-core/computed/metrics/lantern-max-potential-fid.js +1 -1
- package/lighthouse-core/computed/metrics/lantern-metric.js +3 -5
- package/lighthouse-core/computed/metrics/lantern-speed-index.js +1 -1
- package/lighthouse-core/computed/metrics/lantern-total-blocking-time.js +1 -1
- package/lighthouse-core/computed/metrics/largest-contentful-paint-all-frames.js +1 -1
- package/lighthouse-core/computed/metrics/largest-contentful-paint.js +1 -1
- package/lighthouse-core/computed/metrics/max-potential-fid.js +1 -1
- package/lighthouse-core/computed/metrics/metric.js +1 -0
- package/lighthouse-core/computed/metrics/speed-index.js +1 -1
- package/lighthouse-core/computed/metrics/timing-summary.js +13 -6
- package/lighthouse-core/computed/metrics/total-blocking-time.js +1 -1
- package/lighthouse-core/computed/page-dependency-graph.js +54 -31
- package/lighthouse-core/gather/driver/execution-context.js +4 -2
- package/lighthouse-core/gather/gatherers/js-usage.js +7 -6
- package/lighthouse-core/gather/gatherers/scripts.js +20 -2
- package/lighthouse-core/lib/dependency-graph/simulator/network-analyzer.js +8 -29
- package/lighthouse-core/lib/navigation-error.js +13 -4
- package/lighthouse-core/util-commonjs.js +20 -18
- package/package.json +1 -1
- package/report/renderer/util.js +20 -18
- package/types/artifacts.d.ts +1 -0
|
@@ -29,7 +29,7 @@ class LargestContentfulPaint extends Audit {
|
|
|
29
29
|
description: str_(UIStrings.description),
|
|
30
30
|
scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
|
|
31
31
|
supportedModes: ['navigation'],
|
|
32
|
-
requiredArtifacts: ['HostUserAgent', 'traces', 'devtoolsLogs', 'GatherContext'],
|
|
32
|
+
requiredArtifacts: ['HostUserAgent', 'traces', 'devtoolsLogs', 'GatherContext', 'URL'],
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -74,7 +74,8 @@ class LargestContentfulPaint extends Audit {
|
|
|
74
74
|
const trace = artifacts.traces[Audit.DEFAULT_PASS];
|
|
75
75
|
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
76
76
|
const gatherContext = artifacts.GatherContext;
|
|
77
|
-
const metricComputationData = {trace, devtoolsLog, gatherContext,
|
|
77
|
+
const metricComputationData = {trace, devtoolsLog, gatherContext,
|
|
78
|
+
settings: context.settings, URL: artifacts.URL};
|
|
78
79
|
|
|
79
80
|
let metricResult;
|
|
80
81
|
try {
|
|
@@ -33,7 +33,7 @@ class MaxPotentialFID extends Audit {
|
|
|
33
33
|
description: str_(UIStrings.description),
|
|
34
34
|
scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
|
|
35
35
|
supportedModes: ['navigation'],
|
|
36
|
-
requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext'],
|
|
36
|
+
requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL'],
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -57,7 +57,8 @@ class MaxPotentialFID extends Audit {
|
|
|
57
57
|
const trace = artifacts.traces[Audit.DEFAULT_PASS];
|
|
58
58
|
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
59
59
|
const gatherContext = artifacts.GatherContext;
|
|
60
|
-
const metricComputationData = {trace, devtoolsLog, gatherContext,
|
|
60
|
+
const metricComputationData = {trace, devtoolsLog, gatherContext,
|
|
61
|
+
settings: context.settings, URL: artifacts.URL};
|
|
61
62
|
const metricResult = await ComputedFid.request(metricComputationData, context);
|
|
62
63
|
|
|
63
64
|
return {
|
|
@@ -28,7 +28,7 @@ class SpeedIndex extends Audit {
|
|
|
28
28
|
description: str_(UIStrings.description),
|
|
29
29
|
scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
|
|
30
30
|
supportedModes: ['navigation'],
|
|
31
|
-
requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext'],
|
|
31
|
+
requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL'],
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
|
|
@@ -67,7 +67,8 @@ class SpeedIndex extends Audit {
|
|
|
67
67
|
const trace = artifacts.traces[Audit.DEFAULT_PASS];
|
|
68
68
|
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
69
69
|
const gatherContext = artifacts.GatherContext;
|
|
70
|
-
const metricComputationData = {trace, devtoolsLog, gatherContext,
|
|
70
|
+
const metricComputationData = {trace, devtoolsLog, gatherContext,
|
|
71
|
+
settings: context.settings, URL: artifacts.URL};
|
|
71
72
|
const metricResult = await ComputedSi.request(metricComputationData, context);
|
|
72
73
|
const options = context.options[context.settings.formFactor];
|
|
73
74
|
|
|
@@ -27,7 +27,7 @@ class TotalBlockingTime extends Audit {
|
|
|
27
27
|
title: str_(i18n.UIStrings.totalBlockingTimeMetric),
|
|
28
28
|
description: str_(UIStrings.description),
|
|
29
29
|
scoreDisplayMode: Audit.SCORING_MODES.NUMERIC,
|
|
30
|
-
requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext'],
|
|
30
|
+
requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL'],
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -88,7 +88,8 @@ class TotalBlockingTime extends Audit {
|
|
|
88
88
|
const trace = artifacts.traces[Audit.DEFAULT_PASS];
|
|
89
89
|
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
90
90
|
const gatherContext = artifacts.GatherContext;
|
|
91
|
-
const metricComputationData = {trace, devtoolsLog, gatherContext,
|
|
91
|
+
const metricComputationData = {trace, devtoolsLog, gatherContext,
|
|
92
|
+
settings: context.settings, URL: artifacts.URL};
|
|
92
93
|
if (
|
|
93
94
|
gatherContext.gatherMode === 'timespan' &&
|
|
94
95
|
context.settings.throttlingMethod === 'simulate'
|
|
@@ -29,7 +29,7 @@ class Metrics extends Audit {
|
|
|
29
29
|
title: 'Metrics',
|
|
30
30
|
description: 'Collects all available metrics.',
|
|
31
31
|
supportedModes: ['navigation'],
|
|
32
|
-
requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext'],
|
|
32
|
+
requiredArtifacts: ['traces', 'devtoolsLogs', 'GatherContext', 'URL'],
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
|
|
@@ -42,8 +42,9 @@ class Metrics extends Audit {
|
|
|
42
42
|
const gatherContext = artifacts.GatherContext;
|
|
43
43
|
const trace = artifacts.traces[Audit.DEFAULT_PASS];
|
|
44
44
|
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
45
|
+
const URL = artifacts.URL;
|
|
45
46
|
const summary = await ComputedTimingSummary
|
|
46
|
-
.request({trace, devtoolsLog, gatherContext, settings: context.settings}, context);
|
|
47
|
+
.request({trace, devtoolsLog, gatherContext, settings: context.settings, URL}, context);
|
|
47
48
|
const metrics = summary.metrics;
|
|
48
49
|
const debugInfo = summary.debugInfo;
|
|
49
50
|
|
|
@@ -47,10 +47,11 @@ class PredictivePerf extends Audit {
|
|
|
47
47
|
const gatherContext = artifacts.GatherContext;
|
|
48
48
|
const trace = artifacts.traces[Audit.DEFAULT_PASS];
|
|
49
49
|
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
50
|
+
const URL = artifacts.URL;
|
|
50
51
|
/** @type {LH.Config.Settings} */
|
|
51
52
|
// @ts-expect-error - TODO(bckenny): allow optional `throttling` settings
|
|
52
53
|
const settings = {}; // Use default settings.
|
|
53
|
-
const computationData = {trace, devtoolsLog, gatherContext, settings};
|
|
54
|
+
const computationData = {trace, devtoolsLog, gatherContext, settings, URL};
|
|
54
55
|
const fcp = await LanternFcp.request(computationData, context);
|
|
55
56
|
const fmp = await LanternFmp.request(computationData, context);
|
|
56
57
|
const tti = await LanternInteractive.request(computationData, context);
|
|
@@ -203,7 +203,7 @@ class PreloadLCPImageAudit extends Audit {
|
|
|
203
203
|
const trace = artifacts.traces[PreloadLCPImageAudit.DEFAULT_PASS];
|
|
204
204
|
const devtoolsLog = artifacts.devtoolsLogs[PreloadLCPImageAudit.DEFAULT_PASS];
|
|
205
205
|
const URL = artifacts.URL;
|
|
206
|
-
const metricData = {trace, devtoolsLog, gatherContext, settings: context.settings};
|
|
206
|
+
const metricData = {trace, devtoolsLog, gatherContext, settings: context.settings, URL};
|
|
207
207
|
const lcpElement = artifacts.TraceElements
|
|
208
208
|
.find(element => element.traceEventType === 'largest-contentful-paint');
|
|
209
209
|
|
|
@@ -93,7 +93,7 @@ class Redirects extends Audit {
|
|
|
93
93
|
const networkRecords = await NetworkRecords.request(devtoolsLog, context);
|
|
94
94
|
const mainResource = await MainResource.request({URL: artifacts.URL, devtoolsLog}, context);
|
|
95
95
|
|
|
96
|
-
const metricComputationData = {trace, devtoolsLog, gatherContext, settings};
|
|
96
|
+
const metricComputationData = {trace, devtoolsLog, gatherContext, settings, URL: artifacts.URL};
|
|
97
97
|
const metricResult = await LanternInteractive.request(metricComputationData, context);
|
|
98
98
|
|
|
99
99
|
/** @type {Map<string, LH.Gatherer.Simulation.NodeTiming>} */
|
|
@@ -140,8 +140,9 @@ class TimingBudget extends Audit {
|
|
|
140
140
|
const gatherContext = artifacts.GatherContext;
|
|
141
141
|
const devtoolsLog = artifacts.devtoolsLogs[Audit.DEFAULT_PASS];
|
|
142
142
|
const trace = artifacts.traces[Audit.DEFAULT_PASS];
|
|
143
|
-
const
|
|
144
|
-
const
|
|
143
|
+
const URL = artifacts.URL;
|
|
144
|
+
const mainResource = await MainResource.request({URL, devtoolsLog}, context);
|
|
145
|
+
const data = {trace, devtoolsLog, gatherContext, settings: context.settings, URL};
|
|
145
146
|
const summary = (await TimingSummary.request(data, context)).metrics;
|
|
146
147
|
const budget = Budget.getMatchingBudget(context.settings.budgets, mainResource.url);
|
|
147
148
|
|
|
@@ -123,7 +123,7 @@ class UsesRelPreconnectAudit extends Audit {
|
|
|
123
123
|
MainResource.request({devtoolsLog, URL: artifacts.URL}, context),
|
|
124
124
|
LoadSimulator.request({devtoolsLog, settings}, context),
|
|
125
125
|
ProcessedNavigation.request(processedTrace, context),
|
|
126
|
-
PageDependencyGraph.request({trace, devtoolsLog}, context),
|
|
126
|
+
PageDependencyGraph.request({trace, devtoolsLog, URL: artifacts.URL}, context),
|
|
127
127
|
]);
|
|
128
128
|
|
|
129
129
|
const {rtt, additionalRttByOrigin} = loadSimulator.getOptions();
|
|
@@ -217,7 +217,7 @@ class UsesRelPreloadAudit extends Audit {
|
|
|
217
217
|
|
|
218
218
|
const [mainResource, graph, simulator] = await Promise.all([
|
|
219
219
|
MainResource.request({devtoolsLog, URL}, context),
|
|
220
|
-
PageDependencyGraph.request({trace, devtoolsLog}, context),
|
|
220
|
+
PageDependencyGraph.request({trace, devtoolsLog, URL}, context),
|
|
221
221
|
LoadSimulator.request(simulatorOptions, context),
|
|
222
222
|
]);
|
|
223
223
|
|
|
@@ -129,15 +129,8 @@ class CriticalRequestChains {
|
|
|
129
129
|
* @return {Promise<LH.Artifacts.CriticalRequestNode>}
|
|
130
130
|
*/
|
|
131
131
|
static async compute_(data, context) {
|
|
132
|
-
const mainResource = await MainResource.request(
|
|
133
|
-
|
|
134
|
-
devtoolsLog: data.devtoolsLog,
|
|
135
|
-
}, context);
|
|
136
|
-
|
|
137
|
-
const graph = await PageDependencyGraph.request({
|
|
138
|
-
trace: data.trace,
|
|
139
|
-
devtoolsLog: data.devtoolsLog,
|
|
140
|
-
}, context);
|
|
132
|
+
const mainResource = await MainResource.request(data, context);
|
|
133
|
+
const graph = await PageDependencyGraph.request(data, context);
|
|
141
134
|
|
|
142
135
|
return CriticalRequestChains.extractChainsFromGraph(mainResource, graph);
|
|
143
136
|
}
|
|
@@ -22,7 +22,7 @@ class MainResource {
|
|
|
22
22
|
static async compute_(data, context) {
|
|
23
23
|
const finalUrl = data.URL.finalUrl;
|
|
24
24
|
const requests = await NetworkRecords.request(data.devtoolsLog, context);
|
|
25
|
-
const mainResource = NetworkAnalyzer.
|
|
25
|
+
const mainResource = NetworkAnalyzer.findResourceForUrl(requests, finalUrl);
|
|
26
26
|
if (!mainResource) {
|
|
27
27
|
throw new Error('Unable to identify the main resource');
|
|
28
28
|
}
|
|
@@ -33,5 +33,5 @@ class FirstContentfulPaintAllFrames extends NavigationMetric {
|
|
|
33
33
|
|
|
34
34
|
module.exports = makeComputedArtifact(
|
|
35
35
|
FirstContentfulPaintAllFrames,
|
|
36
|
-
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
|
|
36
|
+
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
|
|
37
37
|
);
|
|
@@ -36,5 +36,5 @@ class FirstContentfulPaint extends NavigationMetric {
|
|
|
36
36
|
|
|
37
37
|
module.exports = makeComputedArtifact(
|
|
38
38
|
FirstContentfulPaint,
|
|
39
|
-
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
|
|
39
|
+
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
|
|
40
40
|
);
|
|
@@ -40,5 +40,5 @@ class FirstMeaningfulPaint extends NavigationMetric {
|
|
|
40
40
|
|
|
41
41
|
module.exports = makeComputedArtifact(
|
|
42
42
|
FirstMeaningfulPaint,
|
|
43
|
-
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
|
|
43
|
+
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
|
|
44
44
|
);
|
|
@@ -183,7 +183,7 @@ class Interactive extends NavigationMetric {
|
|
|
183
183
|
|
|
184
184
|
module.exports = makeComputedArtifact(
|
|
185
185
|
Interactive,
|
|
186
|
-
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
|
|
186
|
+
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
|
|
187
187
|
);
|
|
188
188
|
|
|
189
189
|
/**
|
|
@@ -200,5 +200,5 @@ class LanternFirstContentfulPaint extends LanternMetric {
|
|
|
200
200
|
|
|
201
201
|
module.exports = makeComputedArtifact(
|
|
202
202
|
LanternFirstContentfulPaint,
|
|
203
|
-
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
|
|
203
|
+
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
|
|
204
204
|
);
|
|
@@ -79,5 +79,5 @@ class LanternFirstMeaningfulPaint extends LanternMetric {
|
|
|
79
79
|
|
|
80
80
|
module.exports = makeComputedArtifact(
|
|
81
81
|
LanternFirstMeaningfulPaint,
|
|
82
|
-
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
|
|
82
|
+
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
|
|
83
83
|
);
|
|
@@ -109,5 +109,5 @@ class LanternInteractive extends LanternMetric {
|
|
|
109
109
|
|
|
110
110
|
module.exports = makeComputedArtifact(
|
|
111
111
|
LanternInteractive,
|
|
112
|
-
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
|
|
112
|
+
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
|
|
113
113
|
);
|
|
@@ -107,5 +107,5 @@ class LanternLargestContentfulPaint extends LanternMetric {
|
|
|
107
107
|
|
|
108
108
|
module.exports = makeComputedArtifact(
|
|
109
109
|
LanternLargestContentfulPaint,
|
|
110
|
-
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
|
|
110
|
+
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
|
|
111
111
|
);
|
|
@@ -89,5 +89,5 @@ class LanternMaxPotentialFID extends LanternMetricArtifact {
|
|
|
89
89
|
|
|
90
90
|
module.exports = makeComputedArtifact(
|
|
91
91
|
LanternMaxPotentialFID,
|
|
92
|
-
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
|
|
92
|
+
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
|
|
93
93
|
);
|
|
@@ -101,17 +101,15 @@ class LanternMetricArtifact {
|
|
|
101
101
|
static async computeMetricWithGraphs(data, context, extras) {
|
|
102
102
|
// TODO: remove this fallback when lighthouse-pub-ads plugin can update.
|
|
103
103
|
const gatherContext = data.gatherContext || {gatherMode: 'navigation'};
|
|
104
|
-
const {trace, devtoolsLog, settings} = data;
|
|
105
104
|
if (gatherContext.gatherMode !== 'navigation') {
|
|
106
105
|
throw new Error(`Lantern metrics can only be computed on navigations`);
|
|
107
106
|
}
|
|
108
107
|
|
|
109
108
|
const metricName = this.name.replace('Lantern', '');
|
|
110
|
-
const graph = await PageDependencyGraph.request(
|
|
111
|
-
const processedTrace = await ProcessedTrace.request(trace, context);
|
|
109
|
+
const graph = await PageDependencyGraph.request(data, context);
|
|
110
|
+
const processedTrace = await ProcessedTrace.request(data.trace, context);
|
|
112
111
|
const processedNavigation = await ProcessedNavigation.request(processedTrace, context);
|
|
113
|
-
const simulator = data.simulator ||
|
|
114
|
-
(await LoadSimulator.request({devtoolsLog, settings}, context));
|
|
112
|
+
const simulator = data.simulator || (await LoadSimulator.request(data, context));
|
|
115
113
|
|
|
116
114
|
const optimisticGraph = this.getOptimisticGraph(graph, processedNavigation);
|
|
117
115
|
const pessimisticGraph = this.getPessimisticGraph(graph, processedNavigation);
|
|
@@ -146,5 +146,5 @@ class LanternSpeedIndex extends LanternMetric {
|
|
|
146
146
|
|
|
147
147
|
module.exports = makeComputedArtifact(
|
|
148
148
|
LanternSpeedIndex,
|
|
149
|
-
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
|
|
149
|
+
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
|
|
150
150
|
);
|
|
@@ -122,5 +122,5 @@ class LanternTotalBlockingTime extends LanternMetric {
|
|
|
122
122
|
|
|
123
123
|
module.exports = makeComputedArtifact(
|
|
124
124
|
LanternTotalBlockingTime,
|
|
125
|
-
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
|
|
125
|
+
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
|
|
126
126
|
);
|
|
@@ -41,5 +41,5 @@ class LargestContentfulPaintAllFrames extends NavigationMetric {
|
|
|
41
41
|
|
|
42
42
|
module.exports = makeComputedArtifact(
|
|
43
43
|
LargestContentfulPaintAllFrames,
|
|
44
|
-
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
|
|
44
|
+
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
|
|
45
45
|
);
|
|
@@ -48,5 +48,5 @@ class LargestContentfulPaint extends NavigationMetric {
|
|
|
48
48
|
|
|
49
49
|
module.exports = makeComputedArtifact(
|
|
50
50
|
LargestContentfulPaint,
|
|
51
|
-
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
|
|
51
|
+
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
|
|
52
52
|
);
|
|
@@ -41,5 +41,5 @@ class MaxPotentialFID extends NavigationMetric {
|
|
|
41
41
|
|
|
42
42
|
module.exports = makeComputedArtifact(
|
|
43
43
|
MaxPotentialFID,
|
|
44
|
-
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
|
|
44
|
+
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
|
|
45
45
|
);
|
|
@@ -26,11 +26,12 @@ class TimingSummary {
|
|
|
26
26
|
* @param {LH.DevtoolsLog} devtoolsLog
|
|
27
27
|
* @param {LH.Artifacts['GatherContext']} gatherContext
|
|
28
28
|
* @param {ImmutableObject<LH.Config.Settings>} settings
|
|
29
|
+
* @param {LH.Artifacts['URL']} URL
|
|
29
30
|
* @param {LH.Artifacts.ComputedContext} context
|
|
30
31
|
* @return {Promise<{metrics: LH.Artifacts.TimingSummary, debugInfo: Record<string,boolean>}>}
|
|
31
32
|
*/
|
|
32
|
-
static async summarize(trace, devtoolsLog, gatherContext, settings, context) {
|
|
33
|
-
const metricComputationData = {trace, devtoolsLog, gatherContext, settings};
|
|
33
|
+
static async summarize(trace, devtoolsLog, gatherContext, settings, URL, context) {
|
|
34
|
+
const metricComputationData = {trace, devtoolsLog, gatherContext, settings, URL};
|
|
34
35
|
/**
|
|
35
36
|
* @template TArtifacts
|
|
36
37
|
* @template TReturn
|
|
@@ -134,17 +135,23 @@ class TimingSummary {
|
|
|
134
135
|
return {metrics, debugInfo};
|
|
135
136
|
}
|
|
136
137
|
/**
|
|
137
|
-
* @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog, gatherContext: LH.Artifacts['GatherContext']; settings: ImmutableObject<LH.Config.Settings
|
|
138
|
+
* @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog, gatherContext: LH.Artifacts['GatherContext']; settings: ImmutableObject<LH.Config.Settings>, URL: LH.Artifacts['URL']}} data
|
|
138
139
|
* @param {LH.Artifacts.ComputedContext} context
|
|
139
140
|
* @return {Promise<{metrics: LH.Artifacts.TimingSummary, debugInfo: Record<string,boolean>}>}
|
|
140
141
|
*/
|
|
141
142
|
static async compute_(data, context) {
|
|
142
|
-
return TimingSummary.summarize(
|
|
143
|
-
|
|
143
|
+
return TimingSummary.summarize(
|
|
144
|
+
data.trace,
|
|
145
|
+
data.devtoolsLog,
|
|
146
|
+
data.gatherContext,
|
|
147
|
+
data.settings,
|
|
148
|
+
data.URL,
|
|
149
|
+
context
|
|
150
|
+
);
|
|
144
151
|
}
|
|
145
152
|
}
|
|
146
153
|
|
|
147
154
|
module.exports = makeComputedArtifact(
|
|
148
155
|
TimingSummary,
|
|
149
|
-
['devtoolsLog', 'gatherContext', 'settings', 'trace']
|
|
156
|
+
['devtoolsLog', 'gatherContext', 'settings', 'trace', 'URL']
|
|
150
157
|
);
|
|
@@ -70,5 +70,5 @@ class TotalBlockingTime extends ComputedMetric {
|
|
|
70
70
|
|
|
71
71
|
module.exports = makeComputedArtifact(
|
|
72
72
|
TotalBlockingTime,
|
|
73
|
-
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace']
|
|
73
|
+
['devtoolsLog', 'gatherContext', 'settings', 'simulator', 'trace', 'URL']
|
|
74
74
|
);
|
|
@@ -8,13 +8,14 @@
|
|
|
8
8
|
const makeComputedArtifact = require('./computed-artifact.js');
|
|
9
9
|
const NetworkNode = require('../lib/dependency-graph/network-node.js');
|
|
10
10
|
const CPUNode = require('../lib/dependency-graph/cpu-node.js');
|
|
11
|
-
const NetworkAnalyzer = require('../lib/dependency-graph/simulator/network-analyzer.js');
|
|
12
11
|
const TracingProcessor = require('../lib/tracehouse/trace-processor.js');
|
|
13
12
|
const NetworkRequest = require('../lib/network-request.js');
|
|
14
13
|
const ProcessedTrace = require('./processed-trace.js');
|
|
15
14
|
const NetworkRecords = require('./network-records.js');
|
|
15
|
+
const NetworkAnalyzer = require('../lib/dependency-graph/simulator/network-analyzer.js');
|
|
16
16
|
|
|
17
17
|
/** @typedef {import('../lib/dependency-graph/base-node.js').Node} Node */
|
|
18
|
+
/** @typedef {Omit<LH.Artifacts['URL'], 'initialUrl'|'finalUrl'>} URLArtifact */
|
|
18
19
|
|
|
19
20
|
// Shorter tasks have negligible impact on simulation results.
|
|
20
21
|
const SIGNIFICANT_DUR_THRESHOLD_MS = 10;
|
|
@@ -388,37 +389,24 @@ class PageDependencyGraph {
|
|
|
388
389
|
/**
|
|
389
390
|
* @param {LH.Artifacts.ProcessedTrace} processedTrace
|
|
390
391
|
* @param {Array<LH.Artifacts.NetworkRequest>} networkRecords
|
|
392
|
+
* @param {URLArtifact} URL
|
|
391
393
|
* @return {Node}
|
|
392
394
|
*/
|
|
393
|
-
static createGraph(processedTrace, networkRecords) {
|
|
395
|
+
static createGraph(processedTrace, networkRecords, URL) {
|
|
394
396
|
const networkNodeOutput = PageDependencyGraph.getNetworkNodeOutput(networkRecords);
|
|
395
397
|
const cpuNodes = PageDependencyGraph.getCPUNodes(processedTrace);
|
|
398
|
+
const {requestedUrl, mainDocumentUrl} = URL;
|
|
399
|
+
if (!mainDocumentUrl) throw new Error('mainDocumentUrl is required to get the main resource');
|
|
396
400
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
// This will be different from the root request when there are server redirects.
|
|
402
|
-
const mainDocumentRequest = NetworkAnalyzer.findMainDocument(networkRecords);
|
|
403
|
-
const mainDocumentNode = networkNodeOutput.idToNodeMap.get(mainDocumentRequest.requestId);
|
|
404
|
-
if (!mainDocumentNode) {
|
|
405
|
-
// mainDocumentNode should always be found.
|
|
406
|
-
throw new Error('mainDocumentNode not found.');
|
|
407
|
-
}
|
|
401
|
+
const rootRequest = NetworkAnalyzer.findResourceForUrl(networkRecords, requestedUrl);
|
|
402
|
+
if (!rootRequest) throw new Error('rootRequest not found');
|
|
403
|
+
const rootNode = networkNodeOutput.idToNodeMap.get(rootRequest.requestId);
|
|
404
|
+
if (!rootNode) throw new Error('rootNode not found');
|
|
408
405
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
let rootNode;
|
|
414
|
-
if (rootRequest) {
|
|
415
|
-
// rootNode should always be found.
|
|
416
|
-
rootNode = rootRequest && networkNodeOutput.idToNodeMap.get(rootRequest.requestId);
|
|
417
|
-
if (!rootNode) throw new Error('rootNode not found');
|
|
418
|
-
} else {
|
|
419
|
-
// Use main document as root if there were no redirects.
|
|
420
|
-
rootNode = mainDocumentNode;
|
|
421
|
-
}
|
|
406
|
+
const mainDocumentRequest = NetworkAnalyzer.findResourceForUrl(networkRecords, mainDocumentUrl);
|
|
407
|
+
if (!mainDocumentRequest) throw new Error('mainDocumentRequest not found');
|
|
408
|
+
const mainDocumentNode = networkNodeOutput.idToNodeMap.get(mainDocumentRequest.requestId);
|
|
409
|
+
if (!mainDocumentNode) throw new Error('mainDocumentNode not found');
|
|
422
410
|
|
|
423
411
|
PageDependencyGraph.linkNetworkNodes(rootNode, networkNodeOutput);
|
|
424
412
|
PageDependencyGraph.linkCPUNodes(rootNode, networkNodeOutput, cpuNodes);
|
|
@@ -464,23 +452,58 @@ class PageDependencyGraph {
|
|
|
464
452
|
}
|
|
465
453
|
|
|
466
454
|
/**
|
|
467
|
-
*
|
|
455
|
+
* Recalculate `artifacts.URL` for clients that don't provide it.
|
|
456
|
+
*
|
|
457
|
+
* @param {LH.DevtoolsLog} devtoolsLog
|
|
458
|
+
* @param {LH.Artifacts.NetworkRequest[]} networkRecords
|
|
459
|
+
* @param {LH.Artifacts.ProcessedTrace} processedTrace
|
|
460
|
+
* @return {URLArtifact}
|
|
461
|
+
*/
|
|
462
|
+
static getDocumentUrls(devtoolsLog, networkRecords, processedTrace) {
|
|
463
|
+
const mainFrameId = processedTrace.mainFrameIds.frameId;
|
|
464
|
+
|
|
465
|
+
/** @type {string|undefined} */
|
|
466
|
+
let requestedUrl;
|
|
467
|
+
/** @type {string|undefined} */
|
|
468
|
+
let mainDocumentUrl;
|
|
469
|
+
for (const event of devtoolsLog) {
|
|
470
|
+
if (event.method === 'Page.frameNavigated' && event.params.frame.id === mainFrameId) {
|
|
471
|
+
const {url} = event.params.frame;
|
|
472
|
+
// Only set requestedUrl on the first main frame navigation.
|
|
473
|
+
if (!requestedUrl) requestedUrl = url;
|
|
474
|
+
mainDocumentUrl = url;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
if (!requestedUrl || !mainDocumentUrl) throw new Error('No main frame navigations found');
|
|
478
|
+
|
|
479
|
+
const initialRequest = NetworkAnalyzer.findResourceForUrl(networkRecords, requestedUrl);
|
|
480
|
+
if (initialRequest?.redirects?.length) requestedUrl = initialRequest.redirects[0].url;
|
|
481
|
+
|
|
482
|
+
return {requestedUrl, mainDocumentUrl};
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog, URL: LH.Artifacts['URL']}} data
|
|
468
487
|
* @param {LH.Artifacts.ComputedContext} context
|
|
469
488
|
* @return {Promise<Node>}
|
|
470
489
|
*/
|
|
471
490
|
static async compute_(data, context) {
|
|
472
|
-
const trace = data
|
|
473
|
-
const devtoolsLog = data.devtoolsLog;
|
|
491
|
+
const {trace, devtoolsLog} = data;
|
|
474
492
|
const [processedTrace, networkRecords] = await Promise.all([
|
|
475
493
|
ProcessedTrace.request(trace, context),
|
|
476
494
|
NetworkRecords.request(devtoolsLog, context),
|
|
477
495
|
]);
|
|
478
496
|
|
|
479
|
-
|
|
497
|
+
// COMPAT: Backport for pre-10.0 clients that don't pass the URL artifact here (e.g. pubads).
|
|
498
|
+
// Calculates the URL artifact from the processed trace and DT log.
|
|
499
|
+
const URL = data.URL ||
|
|
500
|
+
PageDependencyGraph.getDocumentUrls(devtoolsLog, networkRecords, processedTrace);
|
|
501
|
+
|
|
502
|
+
return PageDependencyGraph.createGraph(processedTrace, networkRecords, URL);
|
|
480
503
|
}
|
|
481
504
|
}
|
|
482
505
|
|
|
483
|
-
module.exports = makeComputedArtifact(PageDependencyGraph, ['devtoolsLog', 'trace']);
|
|
506
|
+
module.exports = makeComputedArtifact(PageDependencyGraph, ['devtoolsLog', 'trace', 'URL']);
|
|
484
507
|
|
|
485
508
|
/**
|
|
486
509
|
* @typedef {Object} NetworkNodeOutput
|
|
@@ -97,7 +97,8 @@ class ExecutionContext {
|
|
|
97
97
|
.catch(${pageFunctions.wrapRuntimeEvalErrorInBrowserString})
|
|
98
98
|
.then(resolve);
|
|
99
99
|
});
|
|
100
|
-
}())
|
|
100
|
+
}())
|
|
101
|
+
//# sourceURL=_lighthouse-eval.js`,
|
|
101
102
|
includeCommandLineAPI: true,
|
|
102
103
|
awaitPromise: true,
|
|
103
104
|
returnByValue: true,
|
|
@@ -195,7 +196,8 @@ class ExecutionContext {
|
|
|
195
196
|
${ExecutionContext._cachedNativesPreamble};
|
|
196
197
|
${depsSerialized};
|
|
197
198
|
(${mainFn})(${argsSerialized});
|
|
198
|
-
})()
|
|
199
|
+
})()
|
|
200
|
+
//# sourceURL=_lighthouse-eval.js`;
|
|
199
201
|
|
|
200
202
|
await this._session.sendCommand('Page.addScriptToEvaluateOnNewDocument', {source: expression});
|
|
201
203
|
}
|
|
@@ -50,12 +50,13 @@ class JsUsage extends FRGatherer {
|
|
|
50
50
|
const usageByScriptId = {};
|
|
51
51
|
|
|
52
52
|
for (const scriptUsage of this._scriptUsages) {
|
|
53
|
-
// If `url` is blank, that means the script was
|
|
54
|
-
//
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
// If `url` is blank, that means the script was dynamically
|
|
54
|
+
// created (eval, new Function, onload, ...)
|
|
55
|
+
if (scriptUsage.url === '' || scriptUsage.url === '_lighthouse-eval.js') {
|
|
56
|
+
// We currently don't consider coverage of dynamic scripts, and we definitely don't want
|
|
57
|
+
// coverage of code Lighthouse ran to inspect the page, so we ignore this ScriptCoverage.
|
|
58
|
+
// Audits would work the same without this, it is only an optimization (not tracking coverage
|
|
59
|
+
// for scripts we don't care about).
|
|
59
60
|
continue;
|
|
60
61
|
}
|
|
61
62
|
|
|
@@ -28,6 +28,23 @@ async function runInSeriesOrParallel(values, promiseMapper, runInSeries) {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Returns true if the script was created via our own calls
|
|
33
|
+
* to Runtime.evaluate.
|
|
34
|
+
* @param {LH.Crdp.Debugger.ScriptParsedEvent} script
|
|
35
|
+
*/
|
|
36
|
+
function isLighthouseRuntimeEvaluateScript(script) {
|
|
37
|
+
// Scripts created by Runtime.evaluate that run on the main session/frame
|
|
38
|
+
// result in an empty string for the embedderName.
|
|
39
|
+
// Or, it means the script was dynamically created (eval, new Function, onload, ...)
|
|
40
|
+
if (!script.embedderName) return true;
|
|
41
|
+
|
|
42
|
+
// Otherwise, when running our own code inside other frames, the embedderName
|
|
43
|
+
// is set to the frame's url. In that case, we rely on the special sourceURL that
|
|
44
|
+
// we set.
|
|
45
|
+
return script.hasSourceURL && script.url === '_lighthouse-eval.js';
|
|
46
|
+
}
|
|
47
|
+
|
|
31
48
|
/**
|
|
32
49
|
* @fileoverview Gets JavaScript file contents.
|
|
33
50
|
*/
|
|
@@ -68,8 +85,9 @@ class Scripts extends FRGatherer {
|
|
|
68
85
|
// it also blocks scripts from the same origin but that happen to run in a different process,
|
|
69
86
|
// like a worker.
|
|
70
87
|
if (event.method === 'Debugger.scriptParsed' && !sessionId) {
|
|
71
|
-
|
|
72
|
-
|
|
88
|
+
if (!isLighthouseRuntimeEvaluateScript(event.params)) {
|
|
89
|
+
this._scriptParsedEvents.push(event.params);
|
|
90
|
+
}
|
|
73
91
|
}
|
|
74
92
|
}
|
|
75
93
|
|