Skip to content

Commit

Permalink
core(lantern): remove usage of Lighthouse's ProcessedNavigation (#16048)
Browse files Browse the repository at this point in the history
  • Loading branch information
connorjclark committed Jun 7, 2024
1 parent 4d09dac commit 322a3b7
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 15 deletions.
3 changes: 1 addition & 2 deletions core/audits/redirects.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class Redirects extends Audit {

const processedTrace = await ProcessedTrace.request(trace, context);
const networkRecords = await NetworkRecords.request(devtoolsLog, context);
const documentRequests = Redirects.getDocumentRequestChain(networkRecords, processedTrace);

const metricComputationData = {trace, devtoolsLog, gatherContext, settings, URL: artifacts.URL};
const metricResult = await LanternInteractive.request(metricComputationData, context);
Expand All @@ -102,8 +103,6 @@ class Redirects extends Audit {
}
}

const documentRequests = Redirects.getDocumentRequestChain(networkRecords, processedTrace);

let totalWastedMs = 0;
const tableRows = [];

Expand Down
5 changes: 4 additions & 1 deletion core/computed/metrics/lantern-metric.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {LighthouseError} from '../../lib/lh-error.js';
import {LoadSimulator} from '../load-simulator.js';
import {ProcessedNavigation} from '../processed-navigation.js';
import {PageDependencyGraph} from '../page-dependency-graph.js';
import {TraceEngineResult} from '../trace-engine-result.js';
import {createProcessedNavigation} from '../../lib/lantern/lantern.js';

/**
* @param {LH.Artifacts.MetricComputationDataInput} data
Expand Down Expand Up @@ -36,7 +38,8 @@ async function getComputationDataParamsFromTrace(data, context) {
}

const graph = await PageDependencyGraph.request({...data, fromTrace: true}, context);
const processedNavigation = await ProcessedNavigation.request(data.trace, context);
const traceEngineResult = await TraceEngineResult.request(data, context);
const processedNavigation = createProcessedNavigation(traceEngineResult);
const simulator = data.simulator || (await LoadSimulator.request(data, context));

return {simulator, graph, processedNavigation};
Expand Down
47 changes: 47 additions & 0 deletions core/lib/lantern/lantern.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
* SPDX-License-Identifier: Apache-2.0
*/

import * as Lantern from './types/lantern.js';

/** @typedef {import('@paulirish/trace_engine/models/trace/handlers/PageLoadMetricsHandler.js').MetricName} MetricName */
/** @typedef {import('@paulirish/trace_engine/models/trace/handlers/PageLoadMetricsHandler.js').MetricScore} MetricScore */

/** @type {LH.Util.SelfMap<LH.Crdp.Network.ResourceType>} */
const NetworkRequestTypes = {
XHR: 'XHR',
Expand All @@ -26,6 +31,48 @@ const NetworkRequestTypes = {
Prefetch: 'Prefetch',
};

/**
* @param {LH.Artifacts.TraceEngineResult} traceEngineResult
* @return {Lantern.Simulation.ProcessedNavigation}
*/
function createProcessedNavigation(traceEngineResult) {
const Meta = traceEngineResult.data.Meta;
const frameId = Meta.mainFrameId;
const scoresByNav = traceEngineResult.data.PageLoadMetrics.metricScoresByFrameId.get(frameId);
if (!scoresByNav) {
throw new Error('missing metric scores for main frame');
}

const lastNavigationId = Meta.mainFrameNavigations.at(-1)?.args.data?.navigationId;
const scores = lastNavigationId && scoresByNav.get(lastNavigationId);
if (!scores) {
throw new Error('missing metric scores for specified navigation');
}

/** @param {MetricName} metric */
const getTimestampOrUndefined = metric => {
const metricScore = scores.get(metric);
if (!metricScore?.event) return;
return metricScore.event.ts;
};
/** @param {MetricName} metric */
const getTimestamp = metric => {
const metricScore = scores.get(metric);
if (!metricScore?.event) throw new Error(`missing metric: ${metric}`);
return metricScore.event.ts;
};
// TODO: should use `MetricName.LCP`, but it is a const enum.
const FCP = /** @type {MetricName} */('FCP');
const LCP = /** @type {MetricName} */('LCP');
return {
timestamps: {
firstContentfulPaint: getTimestamp(FCP),
largestContentfulPaint: getTimestampOrUndefined(LCP),
},
};
}

export {
NetworkRequestTypes,
createProcessedNavigation,
};
4 changes: 2 additions & 2 deletions core/lib/lantern/metric.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class Metric {

/**
* @param {Node} dependencyGraph
* @param {LH.Artifacts.ProcessedNavigation} processedNavigation
* @param {Lantern.Simulation.ProcessedNavigation} processedNavigation
* @return {Node}
*/
static getOptimisticGraph(dependencyGraph, processedNavigation) { // eslint-disable-line no-unused-vars
Expand All @@ -73,7 +73,7 @@ class Metric {

/**
* @param {Node} dependencyGraph
* @param {LH.Artifacts.ProcessedNavigation} processedNavigation
* @param {Lantern.Simulation.ProcessedNavigation} processedNavigation
* @return {Node}
*/
static getPessimisticGraph(dependencyGraph, processedNavigation) { // eslint-disable-line no-unused-vars
Expand Down
4 changes: 2 additions & 2 deletions core/lib/lantern/metrics/first-contentful-paint.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ class FirstContentfulPaint extends Metric {

/**
* @param {Node} dependencyGraph
* @param {LH.Artifacts.ProcessedNavigation} processedNavigation
* @param {Lantern.Simulation.ProcessedNavigation} processedNavigation
* @return {Node}
*/
static getOptimisticGraph(dependencyGraph, processedNavigation) {
Expand All @@ -186,7 +186,7 @@ class FirstContentfulPaint extends Metric {

/**
* @param {Node} dependencyGraph
* @param {LH.Artifacts.ProcessedNavigation} processedNavigation
* @param {Lantern.Simulation.ProcessedNavigation} processedNavigation
* @return {Node}
*/
static getPessimisticGraph(dependencyGraph, processedNavigation) {
Expand Down
4 changes: 2 additions & 2 deletions core/lib/lantern/metrics/largest-contentful-paint.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class LargestContentfulPaint extends Metric {

/**
* @param {Node} dependencyGraph
* @param {LH.Artifacts.ProcessedNavigation} processedNavigation
* @param {Lantern.Simulation.ProcessedNavigation} processedNavigation
* @return {Node}
*/
static getOptimisticGraph(dependencyGraph, processedNavigation) {
Expand All @@ -56,7 +56,7 @@ class LargestContentfulPaint extends Metric {

/**
* @param {Node} dependencyGraph
* @param {LH.Artifacts.ProcessedNavigation} processedNavigation
* @param {Lantern.Simulation.ProcessedNavigation} processedNavigation
* @return {Node}
*/
static getPessimisticGraph(dependencyGraph, processedNavigation) {
Expand Down
9 changes: 8 additions & 1 deletion core/lib/lantern/types/lantern.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,16 @@ export namespace Simulation {
nodeTimings: Map<GraphNode<T>, NodeTiming>;
}

interface ProcessedNavigation {
timestamps: {
firstContentfulPaint: number;
largestContentfulPaint?: number;
};
}

interface MetricComputationDataInput {
simulator: Simulator<any>;
graph: GraphNode<any>;
processedNavigation: LH.Artifacts.ProcessedNavigation;
processedNavigation: ProcessedNavigation;
}
}
35 changes: 35 additions & 0 deletions core/test/audits/redirects-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ describe('Performance: Redirects audit', () => {
});
const navStart = trace.traceEvents.find(e => e.name === 'navigationStart');
navStart.args.data.navigationId = '1';
const fcp = trace.traceEvents.find(e => e.name === 'firstContentfulPaint');
fcp.args.data.navigationId = '1';
const lcp = trace.traceEvents.find(e => e.name === 'largestContentfulPaint::Candidate');
lcp.args.data.navigationId = '1';

return {
GatherContext: {gatherMode: 'navigation'},
Expand All @@ -156,6 +160,9 @@ describe('Performance: Redirects audit', () => {

const traceEvents = artifacts.traces.defaultPass.traceEvents;
const navStart = traceEvents.find(e => e.name === 'navigationStart');
const fcp = traceEvents.find(e => e.name === 'firstContentfulPaint');
const lcp = traceEvents.find(e => e.name === 'largestContentfulPaint::Candidate');

const secondNavStart = JSON.parse(JSON.stringify(navStart));
traceEvents.push(secondNavStart);
navStart.args.data.isLoadingMainFrame = true;
Expand All @@ -165,6 +172,16 @@ describe('Performance: Redirects audit', () => {
secondNavStart.args.data.documentLoaderURL = 'https://www.lisairish.com/';
secondNavStart.args.data.navigationId = '2';

const secondFcp = JSON.parse(JSON.stringify(fcp));
traceEvents.push(secondFcp);
secondFcp.args.data.navigationId = '2';
secondFcp.ts += 2;

const secondLcp = JSON.parse(JSON.stringify(lcp));
traceEvents.push(secondLcp);
secondLcp.args.data.navigationId = '2';
secondFcp.ts += 2;

const output = await RedirectsAudit.audit(artifacts, context);
expect(output.details.items).toHaveLength(3);
expect(Math.round(output.score * 100) / 100).toMatchInlineSnapshot(`0`);
Expand Down Expand Up @@ -251,15 +268,33 @@ describe('Performance: Redirects audit', () => {

const traceEvents = artifacts.traces.defaultPass.traceEvents;
const navStart = traceEvents.find(e => e.name === 'navigationStart');
const fcp = traceEvents.find(e => e.name === 'firstContentfulPaint');
const lcp = traceEvents.find(e => e.name === 'largestContentfulPaint::Candidate');

const secondNavStart = JSON.parse(JSON.stringify(navStart));
traceEvents.push(secondNavStart);
secondNavStart.args.data.navigationId = '2';

const secondFcp = JSON.parse(JSON.stringify(fcp));
traceEvents.push(secondFcp);
secondFcp.args.data.navigationId = '2';

const secondLcp = JSON.parse(JSON.stringify(lcp));
traceEvents.push(secondLcp);
secondLcp.args.data.navigationId = '2';

const thirdNavStart = JSON.parse(JSON.stringify(navStart));
traceEvents.push(thirdNavStart);
thirdNavStart.args.data.navigationId = '3';

const thirdFcp = JSON.parse(JSON.stringify(fcp));
traceEvents.push(thirdFcp);
thirdFcp.args.data.navigationId = '3';

const thirdLcp = JSON.parse(JSON.stringify(lcp));
traceEvents.push(thirdLcp);
thirdLcp.args.data.navigationId = '3';

const output = await RedirectsAudit.audit(artifacts, context);
expect(output).toMatchObject({
score: 0,
Expand Down
11 changes: 6 additions & 5 deletions core/test/lib/lantern/metrics/metric-test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
* SPDX-License-Identifier: Apache-2.0
*/

import {ProcessedNavigation} from '../../../../computed/processed-navigation.js';
import {ProcessedTrace} from '../../../../computed/processed-trace.js';
import {TraceEngineResult} from '../../../../computed/trace-engine-result.js';
import {createProcessedNavigation} from '../../../../lib/lantern/lantern.js';
import {PageDependencyGraph} from '../../../../lib/lantern/page-dependency-graph.js';
import {NetworkAnalyzer} from '../../../../lib/lantern/simulator/network-analyzer.js';
import {Simulator} from '../../../../lib/lantern/simulator/simulator.js';
Expand All @@ -18,13 +18,13 @@ import {getURLArtifactFromDevtoolsLog} from '../../../test-utils.js';
// TODO(15841): remove usage of Lighthouse code to create test data

/**
* @param {LH.Artifacts.TraceEngineResult} traceEngineResult
* @param {LH.Artifacts.URL} theURL
* @param {LH.Trace} trace
* @param {LH.Artifacts.ComputedContext} context
*/
async function createGraph(theURL, trace, context) {
async function createGraph(traceEngineResult, theURL, trace, context) {
const {mainThreadEvents} = await ProcessedTrace.request(trace, context);
const traceEngineResult = await TraceEngineResult.request({trace}, context);
return PageDependencyGraph.createGraphFromTrace(
mainThreadEvents, trace, traceEngineResult, theURL);
}
Expand All @@ -38,8 +38,9 @@ async function getComputationDataFromFixture({trace, devtoolsLog, settings, URL}
if (!URL) URL = getURLArtifactFromDevtoolsLog(devtoolsLog);

const context = {settings, computedCache: new Map()};
const {graph, records} = await createGraph(URL, trace, context);
const processedNavigation = await ProcessedNavigation.request(trace, context);
const traceEngineResult = await TraceEngineResult.request({trace}, context);
const {graph, records} = await createGraph(traceEngineResult, URL, trace, context);
const processedNavigation = createProcessedNavigation(traceEngineResult);
const networkAnalysis = NetworkAnalyzer.analyze(records);
const simulator = Simulator.createSimulator({...settings, networkAnalysis});

Expand Down

0 comments on commit 322a3b7

Please sign in to comment.