From 5ef22db220566938a0bcc0c9a6f1f75b1a09feeb Mon Sep 17 00:00:00 2001 From: Connor Clark Date: Tue, 11 Jun 2024 14:37:07 -0700 Subject: [PATCH] core(lantern): remove all LH types (#16061) --- .eslintrc.cjs | 2 +- core/audits/long-tasks.js | 9 +- core/computed/tbt-impact-tasks.js | 3 +- core/lib/lantern-trace-saver.js | 2 +- core/lib/lantern/cpu-node.js | 10 +-- core/lib/lantern/lantern.js | 4 +- core/lib/lantern/metric.js | 8 +- core/lib/lantern/metrics/interactive.js | 10 +-- .../metrics/largest-contentful-paint.js | 8 +- core/lib/lantern/metrics/max-potential-fid.js | 10 +-- core/lib/lantern/metrics/speed-index.js | 12 +-- .../lantern/metrics/total-blocking-time.js | 10 +-- core/lib/lantern/page-dependency-graph.js | 57 ++++++++++--- .../lib/lantern/simulator/network-analyzer.js | 4 +- core/lib/lantern/simulator/simulator.js | 2 +- .../lantern/trace-engine-computation-data.js | 22 +++-- core/lib/lantern/types/lantern.d.ts | 82 +++++++++++++++++-- .../lib/lantern/metrics/metric-test-utils.js | 5 +- package.json | 6 +- types/artifacts.d.ts | 10 +-- yarn.lock | 8 +- 21 files changed, 196 insertions(+), 88 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index e565301f019e..35d310035048 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -76,7 +76,7 @@ module.exports = { vars: 'all', args: 'after-used', argsIgnorePattern: '(^reject$|^_+$)', - varsIgnorePattern: '(^_$|^LH$|^Lantern$|^TraceEngine$)', + varsIgnorePattern: '(^_$|^LH$|^Lantern$|^TraceEngine$|^Protocol$)', }], 'no-cond-assign': 2, 'space-infix-ops': 2, diff --git a/core/audits/long-tasks.js b/core/audits/long-tasks.js index 373cda2ebe10..56cb89bafa88 100644 --- a/core/audits/long-tasks.js +++ b/core/audits/long-tasks.js @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import * as Lantern from '../lib/lantern/types/lantern.js'; import {Audit} from './audit.js'; import {NetworkRecords} from '../computed/network-records.js'; import * as i18n from '../lib/i18n/i18n.js'; @@ -85,7 +86,7 @@ class LongTasks extends Audit { * most time will be attributed to 'other' (the category of the top-level * RunTask). See pruning in `PageDependencyGraph.linkCPUNodes`. * @param {LH.Artifacts.TaskNode} task - * @param {Map|undefined} taskTimingsByEvent + * @param {Map|undefined} taskTimingsByEvent * @param {Map} [timeByTaskGroup] * @return {{startTime: number, duration: number, timeByTaskGroup: Map}} */ @@ -116,7 +117,7 @@ class LongTasks extends Audit { /** * @param {Array} longTasks * @param {Set} jsUrls - * @param {Map|undefined} taskTimingsByEvent + * @param {Map|undefined} taskTimingsByEvent * @return {LH.Audit.Details.DebugData} */ static makeDebugData(longTasks, jsUrls, taskTimingsByEvent) { @@ -154,7 +155,7 @@ class LongTasks extends Audit { /** * Get timing from task, overridden by taskTimingsByEvent if provided. * @param {LH.Artifacts.TaskNode} task - * @param {Map|undefined} taskTimingsByEvent + * @param {Map|undefined} taskTimingsByEvent * @return {Timing} */ static getTiming(task, taskTimingsByEvent) { @@ -184,7 +185,7 @@ class LongTasks extends Audit { const metricComputationData = Audit.makeMetricComputationDataInput(artifacts, context); const tbtResult = await TotalBlockingTime.request(metricComputationData, context); - /** @type {Map|undefined} */ + /** @type {Map|undefined} */ let taskTimingsByEvent; if (settings.throttlingMethod === 'simulate') { diff --git a/core/computed/tbt-impact-tasks.js b/core/computed/tbt-impact-tasks.js index 77a053fa2326..bea336fafdce 100644 --- a/core/computed/tbt-impact-tasks.js +++ b/core/computed/tbt-impact-tasks.js @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import * as Lantern from '../lib/lantern/types/lantern.js'; import {makeComputedArtifact} from './computed-artifact.js'; import {MainThreadTasks} from './main-thread-tasks.js'; import {FirstContentfulPaint} from './metrics/first-contentful-paint.js'; @@ -132,7 +133,7 @@ class TBTImpactTasks { /** @type {Map} */ const topLevelTaskToEvent = new Map(); - /** @type {Map} */ + /** @type {Map} */ const traceEventToTask = new Map(); for (const task of tasks) { traceEventToTask.set(task.event, task); diff --git a/core/lib/lantern-trace-saver.js b/core/lib/lantern-trace-saver.js index 82cab33e4b02..6f172bf7e4f9 100644 --- a/core/lib/lantern-trace-saver.js +++ b/core/lib/lantern-trace-saver.js @@ -116,7 +116,7 @@ function convertNodeTimingsToTrace(nodeTimings) { const ts = eventTs + (event.ts - nestedBaseTs) * multiplier; const newEvent = {...event, ...{pid: baseEvent.pid, tid: baseEvent.tid}, ts}; if (event.dur) newEvent.dur = event.dur * multiplier; - events.push(newEvent); + events.push(/** @type {LH.TraceEvent} */(newEvent)); } return events; diff --git a/core/lib/lantern/cpu-node.js b/core/lib/lantern/cpu-node.js index f6a4b08e3c16..9bb381bdf229 100644 --- a/core/lib/lantern/cpu-node.js +++ b/core/lib/lantern/cpu-node.js @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as LH from '../../../types/lh.js'; +import * as Lantern from './types/lantern.js'; import {BaseNode} from './base-node.js'; /** @@ -13,8 +13,8 @@ import {BaseNode} from './base-node.js'; */ class CPUNode extends BaseNode { /** - * @param {LH.TraceEvent} parentEvent - * @param {LH.TraceEvent[]=} childEvents + * @param {Lantern.TraceEvent} parentEvent + * @param {Lantern.TraceEvent[]=} childEvents * @param {number=} correctedEndTs */ constructor(parentEvent, childEvents = [], correctedEndTs) { @@ -53,14 +53,14 @@ class CPUNode extends BaseNode { } /** - * @return {LH.TraceEvent} + * @return {Lantern.TraceEvent} */ get event() { return this._event; } /** - * @return {LH.TraceEvent[]} + * @return {Lantern.TraceEvent[]} */ get childEvents() { return this._childEvents; diff --git a/core/lib/lantern/lantern.js b/core/lib/lantern/lantern.js index 63312ed5cdec..15e1954a7d40 100644 --- a/core/lib/lantern/lantern.js +++ b/core/lib/lantern/lantern.js @@ -4,7 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -/** @type {LH.Util.SelfMap} */ +import * as Lantern from './types/lantern.js'; + +/** @type {Lantern.Util.SelfMap} */ const NetworkRequestTypes = { XHR: 'XHR', Fetch: 'Fetch', diff --git a/core/lib/lantern/metric.js b/core/lib/lantern/metric.js index 9be8cd506f56..e609ae2bd35b 100644 --- a/core/lib/lantern/metric.js +++ b/core/lib/lantern/metric.js @@ -15,9 +15,9 @@ import {RESOURCE_TYPES} from '../../lib/network-request.js'; /** * @typedef Extras * @property {boolean} optimistic - * @property {LH.Artifacts.LanternMetric=} fcpResult - * @property {LH.Artifacts.LanternMetric=} lcpResult - * @property {LH.Artifacts.LanternMetric=} interactiveResult + * @property {Lantern.Metric=} fcpResult + * @property {Lantern.Metric=} lcpResult + * @property {Lantern.Metric=} interactiveResult * @property {number=} observedSpeedIndex */ @@ -92,7 +92,7 @@ class Metric { /** * @param {Lantern.Simulation.MetricComputationDataInput} data * @param {Omit=} extras - * @return {Promise} + * @return {Promise} */ static async compute(data, extras) { const {simulator, graph, processedNavigation} = data; diff --git a/core/lib/lantern/metrics/interactive.js b/core/lib/lantern/metrics/interactive.js index 5449872bbe87..d2293f5181a9 100644 --- a/core/lib/lantern/metrics/interactive.js +++ b/core/lib/lantern/metrics/interactive.js @@ -16,7 +16,7 @@ const CRITICAL_LONG_TASK_THRESHOLD = 20; class Interactive extends Metric { /** - * @return {LH.Gatherer.Simulation.MetricCoefficients} + * @return {Lantern.Simulation.MetricCoefficients} */ static get COEFFICIENTS() { return { @@ -61,9 +61,9 @@ class Interactive extends Metric { } /** - * @param {LH.Gatherer.Simulation.Result} simulationResult + * @param {Lantern.Simulation.Result} simulationResult * @param {import('../metric.js').Extras} extras - * @return {LH.Gatherer.Simulation.Result} + * @return {Lantern.Simulation.Result} */ static getEstimateFromSimulation(simulationResult, extras) { if (!extras.lcpResult) throw new Error('missing lcpResult'); @@ -81,7 +81,7 @@ class Interactive extends Metric { /** * @param {Lantern.Simulation.MetricComputationDataInput} data * @param {Omit=} extras - * @return {Promise} + * @return {Promise} */ static async compute(data, extras) { const lcpResult = extras?.lcpResult; @@ -95,7 +95,7 @@ class Interactive extends Metric { } /** - * @param {LH.Gatherer.Simulation.Result['nodeTimings']} nodeTimings + * @param {Lantern.Simulation.Result['nodeTimings']} nodeTimings * @return {number} */ static getLastLongTaskEndTime(nodeTimings, duration = 50) { diff --git a/core/lib/lantern/metrics/largest-contentful-paint.js b/core/lib/lantern/metrics/largest-contentful-paint.js index 65bb3eb403f7..096e40c3b2bf 100644 --- a/core/lib/lantern/metrics/largest-contentful-paint.js +++ b/core/lib/lantern/metrics/largest-contentful-paint.js @@ -13,7 +13,7 @@ import {LanternError} from '../lantern-error.js'; class LargestContentfulPaint extends Metric { /** - * @return {LH.Gatherer.Simulation.MetricCoefficients} + * @return {Lantern.Simulation.MetricCoefficients} */ static get COEFFICIENTS() { return { @@ -74,8 +74,8 @@ class LargestContentfulPaint extends Metric { } /** - * @param {LH.Gatherer.Simulation.Result} simulationResult - * @return {LH.Gatherer.Simulation.Result} + * @param {Lantern.Simulation.Result} simulationResult + * @return {Lantern.Simulation.Result} */ static getEstimateFromSimulation(simulationResult) { const nodeTimesNotOffscreenImages = Array.from(simulationResult.nodeTimings.entries()) @@ -91,7 +91,7 @@ class LargestContentfulPaint extends Metric { /** * @param {Lantern.Simulation.MetricComputationDataInput} data * @param {Omit=} extras - * @return {Promise} + * @return {Promise} */ static async compute(data, extras) { const fcpResult = extras?.fcpResult; diff --git a/core/lib/lantern/metrics/max-potential-fid.js b/core/lib/lantern/metrics/max-potential-fid.js index affd770f42a7..fa977cc0a3c0 100644 --- a/core/lib/lantern/metrics/max-potential-fid.js +++ b/core/lib/lantern/metrics/max-potential-fid.js @@ -12,7 +12,7 @@ import {BaseNode} from '../base-node.js'; class MaxPotentialFID extends Metric { /** - * @return {LH.Gatherer.Simulation.MetricCoefficients} + * @return {Lantern.Simulation.MetricCoefficients} */ static get COEFFICIENTS() { return { @@ -39,9 +39,9 @@ class MaxPotentialFID extends Metric { } /** - * @param {LH.Gatherer.Simulation.Result} simulation + * @param {Lantern.Simulation.Result} simulation * @param {import('../metric.js').Extras} extras - * @return {LH.Gatherer.Simulation.Result} + * @return {Lantern.Simulation.Result} */ static getEstimateFromSimulation(simulation, extras) { if (!extras.fcpResult) throw new Error('missing fcpResult'); @@ -66,7 +66,7 @@ class MaxPotentialFID extends Metric { /** * @param {Lantern.Simulation.MetricComputationDataInput} data * @param {Omit=} extras - * @return {Promise} + * @return {Promise} */ static compute(data, extras) { const fcpResult = extras?.fcpResult; @@ -78,7 +78,7 @@ class MaxPotentialFID extends Metric { } /** - * @param {LH.Gatherer.Simulation.Result['nodeTimings']} nodeTimings + * @param {Lantern.Simulation.Result['nodeTimings']} nodeTimings * @param {number} fcpTimeInMs * @return {Array<{duration: number}>} */ diff --git a/core/lib/lantern/metrics/speed-index.js b/core/lib/lantern/metrics/speed-index.js index 1154f32f9653..7898913a7801 100644 --- a/core/lib/lantern/metrics/speed-index.js +++ b/core/lib/lantern/metrics/speed-index.js @@ -14,7 +14,7 @@ const mobileSlow4GRtt = 150; class SpeedIndex extends Metric { /** - * @return {LH.Gatherer.Simulation.MetricCoefficients} + * @return {Lantern.Simulation.MetricCoefficients} */ static get COEFFICIENTS() { return { @@ -28,7 +28,7 @@ class SpeedIndex extends Metric { /** * @param {number} rttMs - * @return {LH.Gatherer.Simulation.MetricCoefficients} + * @return {Lantern.Simulation.MetricCoefficients} */ static getScaledCoefficients(rttMs) { // eslint-disable-line no-unused-vars // We want to scale our default coefficients based on the speed of the connection. @@ -70,9 +70,9 @@ class SpeedIndex extends Metric { } /** - * @param {LH.Gatherer.Simulation.Result} simulationResult + * @param {Lantern.Simulation.Result} simulationResult * @param {import('../metric.js').Extras} extras - * @return {LH.Gatherer.Simulation.Result} + * @return {Lantern.Simulation.Result} */ static getEstimateFromSimulation(simulationResult, extras) { if (!extras.fcpResult) throw new Error('missing fcpResult'); @@ -91,7 +91,7 @@ class SpeedIndex extends Metric { /** * @param {Lantern.Simulation.MetricComputationDataInput} data * @param {Omit=} extras - * @return {Promise} + * @return {Promise} */ static async compute(data, extras) { const fcpResult = extras?.fcpResult; @@ -115,7 +115,7 @@ class SpeedIndex extends Metric { * different methods. Read more in the evaluation doc. * * @see https://docs.google.com/document/d/1qJWXwxoyVLVadezIp_Tgdk867G3tDNkkVRvUJSH3K1E/edit# - * @param {LH.Gatherer.Simulation.Result['nodeTimings']} nodeTimings + * @param {Lantern.Simulation.Result['nodeTimings']} nodeTimings * @param {number} fcpTimeInMs * @return {number} */ diff --git a/core/lib/lantern/metrics/total-blocking-time.js b/core/lib/lantern/metrics/total-blocking-time.js index 8c08280cc8c7..59309a2621b5 100644 --- a/core/lib/lantern/metrics/total-blocking-time.js +++ b/core/lib/lantern/metrics/total-blocking-time.js @@ -13,7 +13,7 @@ import {BLOCKING_TIME_THRESHOLD, calculateSumOfBlockingTime} from '../tbt-utils. class TotalBlockingTime extends Metric { /** - * @return {LH.Gatherer.Simulation.MetricCoefficients} + * @return {Lantern.Simulation.MetricCoefficients} */ static get COEFFICIENTS() { return { @@ -40,9 +40,9 @@ class TotalBlockingTime extends Metric { } /** - * @param {LH.Gatherer.Simulation.Result} simulation + * @param {Lantern.Simulation.Result} simulation * @param {import('../metric.js').Extras} extras - * @return {LH.Gatherer.Simulation.Result} + * @return {Lantern.Simulation.Result} */ static getEstimateFromSimulation(simulation, extras) { if (!extras.fcpResult) throw new Error('missing fcpResult'); @@ -84,7 +84,7 @@ class TotalBlockingTime extends Metric { /** * @param {Lantern.Simulation.MetricComputationDataInput} data * @param {Omit=} extras - * @return {Promise} + * @return {Promise} */ static async compute(data, extras) { const fcpResult = extras?.fcpResult; @@ -101,7 +101,7 @@ class TotalBlockingTime extends Metric { } /** - * @param {LH.Gatherer.Simulation.Result['nodeTimings']} nodeTimings + * @param {Lantern.Simulation.Result['nodeTimings']} nodeTimings * @param {number} minDurationMs */ static getTopLevelEvents(nodeTimings, minDurationMs) { diff --git a/core/lib/lantern/page-dependency-graph.js b/core/lib/lantern/page-dependency-graph.js index c7359c84257a..a3def68f32af 100644 --- a/core/lib/lantern/page-dependency-graph.js +++ b/core/lib/lantern/page-dependency-graph.js @@ -8,11 +8,18 @@ import * as Lantern from './types/lantern.js'; import {NetworkRequestTypes} from './lantern.js'; import {NetworkNode} from './network-node.js'; import {CPUNode} from './cpu-node.js'; -import {TraceProcessor} from '../tracehouse/trace-processor.js'; import {NetworkAnalyzer} from './simulator/network-analyzer.js'; +// COMPAT: m71+ We added RunTask to `disabled-by-default-lighthouse` +const SCHEDULABLE_TASK_TITLE_LH = 'RunTask'; +// m69-70 DoWork is different and we now need RunTask, see https://bugs.chromium.org/p/chromium/issues/detail?id=871204#c11 +const SCHEDULABLE_TASK_TITLE_ALT1 = 'ThreadControllerImpl::RunTask'; +// In m66-68 refactored to this task title, https://crrev.com/c/883346 +const SCHEDULABLE_TASK_TITLE_ALT2 = 'ThreadControllerImpl::DoWork'; +// m65 and earlier +const SCHEDULABLE_TASK_TITLE_ALT3 = 'TaskQueueManager::ProcessTaskFromWorkQueue'; + /** @typedef {import('./base-node.js').Node} Node */ -/** @typedef {Omit} URLArtifact */ /** * @typedef {Object} NetworkNodeOutput @@ -109,7 +116,31 @@ class PageDependencyGraph { } /** - * @param {LH.TraceEvent[]} mainThreadEvents + * @param {Lantern.TraceEvent} evt + * @return {boolean} + */ + static isScheduleableTask(evt) { + return evt.name === SCHEDULABLE_TASK_TITLE_LH || + evt.name === SCHEDULABLE_TASK_TITLE_ALT1 || + evt.name === SCHEDULABLE_TASK_TITLE_ALT2 || + evt.name === SCHEDULABLE_TASK_TITLE_ALT3; + } + + /** + * There should *always* be at least one top level event, having 0 typically means something is + * drastically wrong with the trace and we should just give up early and loudly. + * + * @param {Lantern.TraceEvent[]} events + */ + static assertHasToplevelEvents(events) { + const hasToplevelTask = events.some(this.isScheduleableTask); + if (!hasToplevelTask) { + throw new Error('Could not find any top level events'); + } + } + + /** + * @param {Lantern.TraceEvent[]} mainThreadEvents * @return {Array} */ static getCPUNodes(mainThreadEvents) { @@ -117,14 +148,14 @@ class PageDependencyGraph { const nodes = []; let i = 0; - TraceProcessor.assertHasToplevelEvents(mainThreadEvents); + PageDependencyGraph.assertHasToplevelEvents(mainThreadEvents); while (i < mainThreadEvents.length) { const evt = mainThreadEvents[i]; i++; // Skip all trace events that aren't schedulable tasks with sizable duration - if (!TraceProcessor.isScheduleableTask(evt) || !evt.dur) { + if (!PageDependencyGraph.isScheduleableTask(evt) || !evt.dur) { continue; } @@ -132,23 +163,25 @@ class PageDependencyGraph { let correctedEndTs = undefined; // Capture all events that occurred within the task - /** @type {Array} */ + /** @type {Array} */ const children = []; for ( const endTime = evt.ts + evt.dur; i < mainThreadEvents.length && mainThreadEvents[i].ts < endTime; i++ ) { + const event = mainThreadEvents[i]; + // Temporary fix for a Chrome bug where some RunTask events can be overlapping. // We correct that here be ensuring each RunTask ends at least 1 microsecond before the next // https://github.com/GoogleChrome/lighthouse/issues/15896 // https://issues.chromium.org/issues/329678173 - if (TraceProcessor.isScheduleableTask(mainThreadEvents[i]) && mainThreadEvents[i].dur) { - correctedEndTs = mainThreadEvents[i].ts - 1; + if (PageDependencyGraph.isScheduleableTask(event) && event.dur) { + correctedEndTs = event.ts - 1; break; } - children.push(mainThreadEvents[i]); + children.push(event); } nodes.push(new CPUNode(evt, children, correctedEndTs)); @@ -210,7 +243,7 @@ class PageDependencyGraph { * @param {Array} cpuNodes */ static linkCPUNodes(rootNode, networkNodeOutput, cpuNodes) { - /** @type {Set} */ + /** @type {Set} */ const linkableResourceTypes = new Set([ NetworkRequestTypes.XHR, NetworkRequestTypes.Fetch, NetworkRequestTypes.Script, ]); @@ -506,9 +539,9 @@ class PageDependencyGraph { } /** - * @param {LH.TraceEvent[]} mainThreadEvents + * @param {Lantern.TraceEvent[]} mainThreadEvents * @param {Lantern.NetworkRequest[]} networkRequests - * @param {URLArtifact} URL + * @param {Lantern.Simulation.URL} URL * @return {Node} */ static createGraph(mainThreadEvents, networkRequests, URL) { diff --git a/core/lib/lantern/simulator/network-analyzer.js b/core/lib/lantern/simulator/network-analyzer.js index d790c3a4cd27..5207658faeae 100644 --- a/core/lib/lantern/simulator/network-analyzer.js +++ b/core/lib/lantern/simulator/network-analyzer.js @@ -15,7 +15,7 @@ const DEFAULT_SERVER_RESPONSE_PERCENTAGE = 0.4; /** * For certain resource types, server response time takes up a greater percentage of TTFB (dynamic * assets like HTML documents, XHR/API calls, etc) - * @type {Partial>} + * @type {Partial>} */ const SERVER_RESPONSE_PERCENTAGE_OF_TTFB = { Document: 0.9, @@ -88,7 +88,7 @@ class NetworkAnalyzer { return summaryByKey; } - /** @typedef {{request: Lantern.NetworkRequest, timing: LH.Crdp.Network.ResourceTiming, connectionReused?: boolean}} RequestInfo */ + /** @typedef {{request: Lantern.NetworkRequest, timing: Lantern.ResourceTiming, connectionReused?: boolean}} RequestInfo */ /** * @param {Lantern.NetworkRequest[]} requests diff --git a/core/lib/lantern/simulator/simulator.js b/core/lib/lantern/simulator/simulator.js index 2e94b374d9ad..620d84708d56 100644 --- a/core/lib/lantern/simulator/simulator.js +++ b/core/lib/lantern/simulator/simulator.js @@ -533,7 +533,7 @@ class Simulator { const minimumTime = this._findNextNodeCompletionTime(); totalElapsedTime += minimumTime; - // While this is no longer strictly necessary, it's always better than LH hanging + // While this is no longer strictly necessary, it's always better than hanging if (!Number.isFinite(minimumTime) || iteration > 100000) { throw new Error('Simulation failed, depth exceeded'); } diff --git a/core/lib/lantern/trace-engine-computation-data.js b/core/lib/lantern/trace-engine-computation-data.js index 1f0b44164b8f..f827fea50710 100644 --- a/core/lib/lantern/trace-engine-computation-data.js +++ b/core/lib/lantern/trace-engine-computation-data.js @@ -5,6 +5,7 @@ */ import * as TraceEngine from '@paulirish/trace_engine'; +import * as Protocol from '@paulirish/trace_engine/generated/protocol.js'; import * as Lantern from './types/lantern.js'; import {PageDependencyGraph} from './page-dependency-graph.js'; @@ -71,7 +72,7 @@ function createParsedUrl(url) { /** * Returns a map of `pid` -> `tid[]`. - * @param {LH.Trace} trace + * @param {Lantern.Trace} trace * @return {Map} */ function findWorkerThreads(trace) { @@ -140,6 +141,9 @@ function createLanternRequest(traceEngineData, workerThreads, request) { fromWorker = true; } + // typescript const enums.... gotta stop using those ... + const Other = /** @type {Protocol.Network.InitiatorType.Other} */ ('other'); + // `initiator` in the trace does not contain the stack trace for JS-initiated // requests. Instead, that is stored in the `stackTrace` property of the SyntheticNetworkRequest. // There are some minor differences in the fields, accounted for here. @@ -148,11 +152,11 @@ function createLanternRequest(traceEngineData, workerThreads, request) { // which means less edges in the graph, which mean worse results. // TODO: Should fix in Chromium. /** @type {Lantern.NetworkRequest['initiator']} */ - const initiator = request.args.data.initiator ?? {type: 'other'}; + const initiator = request.args.data.initiator ?? {type: Other}; if (request.args.data.stackTrace) { const callFrames = request.args.data.stackTrace.map(f => { return { - scriptId: String(f.scriptId), + scriptId: /** @type {Protocol.Runtime.ScriptId} */(String(f.scriptId)), url: f.url, lineNumber: f.lineNumber - 1, columnNumber: f.columnNumber - 1, @@ -160,6 +164,7 @@ function createLanternRequest(traceEngineData, workerThreads, request) { }; }); initiator.stack = {callFrames}; + // Note: there is no `parent` to set ... } let resourceType = request.args.data.resourceType; @@ -296,7 +301,7 @@ function linkInitiators(lanternRequests) { } /** - * @param {LH.Trace} trace + * @param {Lantern.Trace} trace * @param {TraceEngine.Handlers.Types.TraceParseData} traceEngineData * @return {Lantern.NetworkRequest[]} */ @@ -390,9 +395,9 @@ function createNetworkRequests(trace, traceEngineData) { } /** - * @param {LH.Trace} trace + * @param {Lantern.Trace} trace * @param {TraceEngine.Handlers.Types.TraceParseData} traceEngineData - * @return {LH.TraceEvent[]} + * @return {Lantern.TraceEvent[]} */ function collectMainThreadEvents(trace, traceEngineData) { const Meta = traceEngineData.Meta; @@ -431,9 +436,9 @@ function collectMainThreadEvents(trace, traceEngineData) { /** * @param {Lantern.NetworkRequest[]} requests - * @param {LH.Trace} trace + * @param {Lantern.Trace} trace * @param {TraceEngine.Handlers.Types.TraceParseData} traceEngineData - * @param {LH.Artifacts.URL=} URL + * @param {Lantern.Simulation.URL=} URL */ function createGraph(requests, trace, traceEngineData, URL) { const mainThreadEvents = collectMainThreadEvents(trace, traceEngineData); @@ -444,7 +449,6 @@ function createGraph(requests, trace, traceEngineData, URL) { URL = { requestedUrl: requests[0].url, mainDocumentUrl: '', - finalDisplayedUrl: '', }; let request = requests[0]; diff --git a/core/lib/lantern/types/lantern.d.ts b/core/lib/lantern/types/lantern.d.ts index f2279891e838..13159f6fb4ae 100644 --- a/core/lib/lantern/types/lantern.d.ts +++ b/core/lib/lantern/types/lantern.d.ts @@ -4,7 +4,58 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as LH from '../../../../types/lh.js'; +import * as Protocol from '@paulirish/trace_engine/generated/protocol.js'; + +declare module Util { + /** An object with the keys in the union K mapped to themselves as values. */ + type SelfMap = { + [P in K]: P; + }; +} + +type TraceEvent = { + name: string; + cat: string; + args: { + name?: string; + fileName?: string; + snapshot?: string; + sync_id?: string; + beginData?: { + frame?: string; + startLine?: number; + url?: string; + }; + data?: { + frame?: string; + readyState?: number; + stackTrace?: { + url: string + }[]; + url?: string; + }; + }; + pid: number; + tid: number; + /** Timestamp of the event in microseconds. */ + ts: number; + dur: number; +} +type Trace = {traceEvents: TraceEvent[]}; +type ResourcePriority = ('VeryLow' | 'Low' | 'Medium' | 'High' | 'VeryHigh'); +type ResourceType = ('Document' | 'Stylesheet' | 'Image' | 'Media' | 'Font' | 'Script' | 'TextTrack' | 'XHR' | 'Fetch' | 'Prefetch' | 'EventSource' | 'WebSocket' | 'Manifest' | 'SignedExchange' | 'Ping' | 'CSPViolationReport' | 'Preflight' | 'Other'); +type InitiatorType = ('parser' | 'script' | 'preload' | 'SignedExchange' | 'preflight' | 'other'); +type ResourceTiming = Protocol.Network.ResourceTiming; +type CallStack = { + callFrames: Array<{ + scriptId: string; + url: string; + lineNumber: number; + columnNumber: number; + functionName: string; + }>; + parent?: CallStack; +} type ParsedURL = { /** @@ -80,24 +131,45 @@ export class NetworkRequest { redirectSource: NetworkRequest | undefined; /** The network request that this one redirected to */ redirectDestination: NetworkRequest | undefined; - initiator: LH.Crdp.Network.Initiator; + // TODO: can't use Protocol.Network.Initiator because of type mismatch in Lighthouse initiator. + initiator: { + type: InitiatorType; + url?: string; + stack?: CallStack; + }; initiatorRequest: NetworkRequest | undefined; /** The chain of network requests that redirected to this one */ redirects: NetworkRequest[] | undefined; - timing: LH.Crdp.Network.ResourceTiming | undefined; + timing: Protocol.Network.ResourceTiming | undefined; /** * Optional value for how long the server took to respond to this request. * When not provided, the server response time is derived from the timing object. */ serverResponseTime?: number; - resourceType: LH.Crdp.Network.ResourceType | undefined; + resourceType: ResourceType | undefined; mimeType: string; - priority: LH.Crdp.Network.ResourcePriority; + priority: ResourcePriority; frameId: string | undefined; fromWorker: boolean; } +interface Metric { + timing: number; + timestamp?: never; + optimisticEstimate: Simulation.Result; + pessimisticEstimate: Simulation.Result; + optimisticGraph: Simulation.GraphNode; + pessimisticGraph: Simulation.GraphNode; +} + export namespace Simulation { + type URL = { + /** URL of the initially requested URL */ + requestedUrl?: string; + /** URL of the last document request */ + mainDocumentUrl?: string; + }; + type GraphNode = import('../base-node.js').Node; type GraphNetworkNode = import('../network-node.js').NetworkNode; type GraphCPUNode = import('../cpu-node.js').CPUNode; diff --git a/core/test/lib/lantern/metrics/metric-test-utils.js b/core/test/lib/lantern/metrics/metric-test-utils.js index 0f1e56a2e4b6..6df630b37f73 100644 --- a/core/test/lib/lantern/metrics/metric-test-utils.js +++ b/core/test/lib/lantern/metrics/metric-test-utils.js @@ -6,6 +6,7 @@ import * as TraceEngine from '@paulirish/trace_engine'; +import * as Lantern from '../../../../lib/lantern/types/lantern.js'; import {NetworkAnalyzer} from '../../../../lib/lantern/simulator/network-analyzer.js'; import {Simulator} from '../../../../lib/lantern/simulator/simulator.js'; import * as TraceEngineComputationData from '../../../../lib/lantern/trace-engine-computation-data.js'; @@ -21,10 +22,10 @@ async function runTraceEngine(traceEvents) { } /** - * @param {{trace: LH.Trace, settings?: LH.Config.Settings, URL?: LH.Artifacts.URL}} opts + * @param {{trace: Lantern.Trace, settings?: Lantern.Simulation.Settings, URL?: Lantern.Simulation.URL}} opts */ async function getComputationDataFromFixture({trace, settings, URL}) { - settings = settings ?? /** @type {LH.Config.Settings} */({}); + settings = settings ?? /** @type {Lantern.Simulation.Settings} */({}); if (!settings.throttlingMethod) settings.throttlingMethod = 'simulate'; const traceEngineData = await runTraceEngine( /** @type {TraceEngine.Types.TraceEvents.TraceEventData[]} */ (trace.traceEvents) diff --git a/package.json b/package.json index 59a6b99a0897..289c8b5e0e91 100644 --- a/package.json +++ b/package.json @@ -187,7 +187,7 @@ "chrome-launcher": "^1.1.1", "configstore": "^5.0.1", "csp_evaluator": "1.1.1", - "devtools-protocol": "0.0.1299070", + "devtools-protocol": "0.0.1312386", "enquirer": "^2.3.6", "http-link-header": "^1.1.1", "intl-messageformat": "^10.5.3", @@ -211,8 +211,8 @@ "yargs-parser": "^21.0.0" }, "resolutions": { - "puppeteer/**/devtools-protocol": "0.0.1299070", - "puppeteer-core/**/devtools-protocol": "0.0.1299070" + "puppeteer/**/devtools-protocol": "0.0.1312386", + "puppeteer-core/**/devtools-protocol": "0.0.1312386" }, "repository": "GoogleChrome/lighthouse", "keywords": [ diff --git a/types/artifacts.d.ts b/types/artifacts.d.ts index 6580caeb3c92..1565e51f1ae3 100644 --- a/types/artifacts.d.ts +++ b/types/artifacts.d.ts @@ -6,6 +6,7 @@ import {Protocol as Crdp} from 'devtools-protocol/types/protocol.js'; import * as TraceEngine from '@paulirish/trace_engine'; +import * as Lantern from '../core/lib/lantern/types/lantern.js'; import {LayoutShiftRootCausesData} from '@paulirish/trace_engine/models/trace/root-causes/LayoutShift.js'; import {parseManifest} from '../core/lib/manifest-parser.js'; @@ -591,14 +592,7 @@ declare module Artifacts { throughput: number; } - interface LanternMetric { - timing: number; - timestamp?: never; - optimisticEstimate: Gatherer.Simulation.Result - pessimisticEstimate: Gatherer.Simulation.Result; - optimisticGraph: Gatherer.Simulation.GraphNode; - pessimisticGraph: Gatherer.Simulation.GraphNode; - } + type LanternMetric = Lantern.Metric; type Speedline = speedline.Output<'speedIndex'>; diff --git a/yarn.lock b/yarn.lock index 9cdb3467bb7c..4845f899a7ee 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2938,10 +2938,10 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= -devtools-protocol@0.0.1286932, devtools-protocol@0.0.1299070: - version "0.0.1299070" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1299070.tgz#b3e4cf0b678a46f0f907ae6e07e03ad3a53c00df" - integrity sha512-+qtL3eX50qsJ7c+qVyagqi7AWMoQCBGNfoyJZMwm/NSXVqLYbuitrWEEIzxfUmTNy7//Xe8yhMmQ+elj3uAqSg== +devtools-protocol@0.0.1286932, devtools-protocol@0.0.1312386: + version "0.0.1312386" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1312386.tgz#5ab824d6f1669ec6c6eb0fba047e73601d969052" + integrity sha512-DPnhUXvmvKT2dFA/j7B+riVLUt9Q6RKJlcppojL5CoRywJJKLDYnRlw0gTFKfgDPHP5E04UoB71SxoJlVZy8FA== diff-sequences@^28.0.2: version "28.0.2"