diff --git a/core/audits/byte-efficiency/byte-efficiency-audit.js b/core/audits/byte-efficiency/byte-efficiency-audit.js index 70e9fd92bb23..cb8193838638 100644 --- a/core/audits/byte-efficiency/byte-efficiency-audit.js +++ b/core/audits/byte-efficiency/byte-efficiency-audit.js @@ -14,7 +14,7 @@ import {LCPImageRecord} from '../../computed/lcp-image-record.js'; const str_ = i18n.createIcuMessageFn(import.meta.url, {}); -/** @typedef {import('../../lib/lantern/simulator/Simulator.js').Simulator} Simulator */ +/** @typedef {import('../../lib/lantern/simulation/Simulator.js').Simulator} Simulator */ /** @typedef {import('../../lib/lantern/BaseNode.js').Node} Node */ // Parameters for log-normal distribution scoring. These values were determined by fitting the diff --git a/core/audits/byte-efficiency/render-blocking-resources.js b/core/audits/byte-efficiency/render-blocking-resources.js index c69e646a8347..e8488ceebc93 100644 --- a/core/audits/byte-efficiency/render-blocking-resources.js +++ b/core/audits/byte-efficiency/render-blocking-resources.js @@ -11,7 +11,7 @@ import {Audit} from '../audit.js'; import * as i18n from '../../lib/i18n/i18n.js'; -import {BaseNode} from '../../lib/lantern/BaseNode.js'; +import {BaseNode} from '../../lib/lantern/lantern.js'; import {UnusedCSS} from '../../computed/unused-css.js'; import {NetworkRequest} from '../../lib/network-request.js'; import {LoadSimulator} from '../../computed/load-simulator.js'; @@ -20,7 +20,7 @@ import {LCPImageRecord} from '../../computed/lcp-image-record.js'; import {NavigationInsights} from '../../computed/navigation-insights.js'; -/** @typedef {import('../../lib/lantern/simulator/Simulator.js').Simulator} Simulator */ +/** @typedef {import('../../lib/lantern/simulation/Simulator.js').Simulator} Simulator */ /** @typedef {import('../../lib/lantern/BaseNode.js').Node} Node */ /** @typedef {import('../../lib/lantern/NetworkNode.js').NetworkNode} NetworkNode */ diff --git a/core/audits/dobetterweb/uses-http2.js b/core/audits/dobetterweb/uses-http2.js index 4c44473e76c2..a399213dcfbd 100644 --- a/core/audits/dobetterweb/uses-http2.js +++ b/core/audits/dobetterweb/uses-http2.js @@ -9,7 +9,7 @@ * origin are over the http/2 protocol. */ -/** @typedef {import('../../lib/lantern/simulator/Simulator.js').Simulator} Simulator */ +/** @typedef {import('../../lib/lantern/simulation/Simulator.js').Simulator} Simulator */ /** @typedef {import('../../lib/lantern/BaseNode.js').Node} Node */ import {Audit} from '../audit.js'; diff --git a/core/audits/long-tasks.js b/core/audits/long-tasks.js index 56cb89bafa88..320bdb93943d 100644 --- a/core/audits/long-tasks.js +++ b/core/audits/long-tasks.js @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as Lantern from '../lib/lantern/types/lantern.js'; +import * as Lantern from '../lib/lantern/lantern.js'; import {Audit} from './audit.js'; import {NetworkRecords} from '../computed/network-records.js'; import * as i18n from '../lib/i18n/i18n.js'; diff --git a/core/computed/document-urls.js b/core/computed/document-urls.js index b003148f7422..bfde1a295206 100644 --- a/core/computed/document-urls.js +++ b/core/computed/document-urls.js @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import {NetworkAnalyzer} from '../lib/lantern/simulator/NetworkAnalyzer.js'; +import * as Lantern from '../lib/lantern/lantern.js'; import {makeComputedArtifact} from './computed-artifact.js'; import {NetworkRecords} from './network-records.js'; import {ProcessedTrace} from './processed-trace.js'; @@ -41,7 +41,8 @@ class DocumentUrls { } if (!requestedUrl || !mainDocumentUrl) throw new Error('No main frame navigations found'); - const initialRequest = NetworkAnalyzer.findResourceForUrl(networkRecords, requestedUrl); + const initialRequest = + Lantern.Simulation.NetworkAnalyzer.findResourceForUrl(networkRecords, requestedUrl); if (initialRequest?.redirects?.length) requestedUrl = initialRequest.redirects[0].url; return {requestedUrl, mainDocumentUrl}; diff --git a/core/computed/load-simulator.js b/core/computed/load-simulator.js index c53bf1c57292..ff969206ce67 100644 --- a/core/computed/load-simulator.js +++ b/core/computed/load-simulator.js @@ -5,18 +5,18 @@ */ import {makeComputedArtifact} from './computed-artifact.js'; -import {Simulator} from '../lib/lantern/simulator/Simulator.js'; +import * as Lantern from '../lib/lantern/lantern.js'; import {NetworkAnalysis} from './network-analysis.js'; class LoadSimulator { /** * @param {{devtoolsLog: LH.DevtoolsLog, settings: LH.Audit.Context['settings']}} data * @param {LH.Artifacts.ComputedContext} context - * @return {Promise} + * @return {Promise} */ static async compute_(data, context) { const networkAnalysis = await NetworkAnalysis.request(data.devtoolsLog, context); - return Simulator.createSimulator({...data.settings, networkAnalysis}); + return Lantern.Simulation.Simulator.createSimulator({...data.settings, networkAnalysis}); } /** diff --git a/core/computed/main-resource.js b/core/computed/main-resource.js index 2c2c777e20ab..0c592e81a7a7 100644 --- a/core/computed/main-resource.js +++ b/core/computed/main-resource.js @@ -4,9 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +import * as Lantern from '../lib/lantern/lantern.js'; import {makeComputedArtifact} from './computed-artifact.js'; import {NetworkRecords} from './network-records.js'; -import {NetworkAnalyzer} from '../lib/lantern/simulator/NetworkAnalyzer.js'; /** * @fileoverview This artifact identifies the main resource on the page. Current solution assumes @@ -28,7 +28,8 @@ class MainResource { // document request, we should return the last candidate here. Besides, the browser // would have evicted the first request by the time `MainDocumentRequest` (a consumer // of this computed artifact) attempts to fetch the contents, resulting in a protocol error. - const mainResource = NetworkAnalyzer.findLastDocumentForUrl(records, mainDocumentUrl); + const mainResource = + Lantern.Simulation.NetworkAnalyzer.findLastDocumentForUrl(records, mainDocumentUrl); if (!mainResource) { throw new Error('Unable to identify the main resource'); } diff --git a/core/computed/metrics/lantern-first-contentful-paint.js b/core/computed/metrics/lantern-first-contentful-paint.js index 0604b4a4acec..a50947ed055c 100644 --- a/core/computed/metrics/lantern-first-contentful-paint.js +++ b/core/computed/metrics/lantern-first-contentful-paint.js @@ -4,13 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ +import * as Lantern from '../../lib/lantern/lantern.js'; import {makeComputedArtifact} from '../computed-artifact.js'; import {getComputationDataParams, lanternErrorAdapter} from './lantern-metric.js'; -import {FirstContentfulPaint} from '../../lib/lantern/metrics/FirstContentfulPaint.js'; /** @typedef {import('../../lib/lantern/Metric.js').Extras} Extras */ -class LanternFirstContentfulPaint extends FirstContentfulPaint { +class LanternFirstContentfulPaint extends Lantern.Metrics.FirstContentfulPaint { /** * @param {LH.Artifacts.MetricComputationDataInput} data * @param {LH.Artifacts.ComputedContext} context diff --git a/core/computed/metrics/lantern-interactive.js b/core/computed/metrics/lantern-interactive.js index e42d574621b2..e6f6f342aa8e 100644 --- a/core/computed/metrics/lantern-interactive.js +++ b/core/computed/metrics/lantern-interactive.js @@ -4,14 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ +import * as Lantern from '../../lib/lantern/lantern.js'; import {makeComputedArtifact} from '../computed-artifact.js'; import {LanternLargestContentfulPaint} from './lantern-largest-contentful-paint.js'; -import {Interactive} from '../../lib/lantern/metrics/Interactive.js'; import {getComputationDataParams, lanternErrorAdapter} from './lantern-metric.js'; /** @typedef {import('../../lib/lantern/Metric.js').Extras} Extras */ -class LanternInteractive extends Interactive { +class LanternInteractive extends Lantern.Metrics.Interactive { /** * @param {LH.Artifacts.MetricComputationDataInput} data * @param {LH.Artifacts.ComputedContext} context diff --git a/core/computed/metrics/lantern-largest-contentful-paint.js b/core/computed/metrics/lantern-largest-contentful-paint.js index 0ad96b7074b3..dc34f1a22581 100644 --- a/core/computed/metrics/lantern-largest-contentful-paint.js +++ b/core/computed/metrics/lantern-largest-contentful-paint.js @@ -4,14 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ +import * as Lantern from '../../lib/lantern/lantern.js'; import {makeComputedArtifact} from '../computed-artifact.js'; -import {LargestContentfulPaint} from '../../lib/lantern/metrics/LargestContentfulPaint.js'; import {getComputationDataParams, lanternErrorAdapter} from './lantern-metric.js'; import {LanternFirstContentfulPaint} from './lantern-first-contentful-paint.js'; /** @typedef {import('../../lib/lantern/Metric.js').Extras} Extras */ -class LanternLargestContentfulPaint extends LargestContentfulPaint { +class LanternLargestContentfulPaint extends Lantern.Metrics.LargestContentfulPaint { /** * @param {LH.Artifacts.MetricComputationDataInput} data * @param {LH.Artifacts.ComputedContext} context diff --git a/core/computed/metrics/lantern-max-potential-fid.js b/core/computed/metrics/lantern-max-potential-fid.js index 14bd8ea26705..d883023d2bd1 100644 --- a/core/computed/metrics/lantern-max-potential-fid.js +++ b/core/computed/metrics/lantern-max-potential-fid.js @@ -4,14 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ +import * as Lantern from '../../lib/lantern/lantern.js'; import {makeComputedArtifact} from '../computed-artifact.js'; -import {MaxPotentialFID} from '../../lib/lantern/metrics/MaxPotentialFID.js'; import {getComputationDataParams, lanternErrorAdapter} from './lantern-metric.js'; import {LanternFirstContentfulPaint} from './lantern-first-contentful-paint.js'; /** @typedef {import('../../lib/lantern/Metric.js').Extras} Extras */ -class LanternMaxPotentialFID extends MaxPotentialFID { +class LanternMaxPotentialFID extends Lantern.Metrics.MaxPotentialFID { /** * @param {LH.Artifacts.MetricComputationDataInput} data * @param {LH.Artifacts.ComputedContext} context diff --git a/core/computed/metrics/lantern-metric.js b/core/computed/metrics/lantern-metric.js index bcd9a08f1984..76a13693b364 100644 --- a/core/computed/metrics/lantern-metric.js +++ b/core/computed/metrics/lantern-metric.js @@ -4,13 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -import {LanternError} from '../../lib/lantern/LanternError.js'; +import * as Lantern from '../../lib/lantern/lantern.js'; 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/TraceEngineComputationData.js'; /** * @param {LH.Artifacts.MetricComputationDataInput} data @@ -39,7 +38,8 @@ async function getComputationDataParamsFromTrace(data, context) { const graph = await PageDependencyGraph.request({...data, fromTrace: true}, context); const traceEngineResult = await TraceEngineResult.request(data, context); - const processedNavigation = createProcessedNavigation(traceEngineResult.data); + const processedNavigation = + Lantern.TraceEngineComputationData.createProcessedNavigation(traceEngineResult.data); const simulator = data.simulator || (await LoadSimulator.request(data, context)); return {simulator, graph, processedNavigation}; @@ -50,7 +50,7 @@ async function getComputationDataParamsFromTrace(data, context) { * @return {never} */ function lanternErrorAdapter(err) { - if (!(err instanceof LanternError)) { + if (!(err instanceof Lantern.Error)) { throw err; } diff --git a/core/computed/metrics/lantern-speed-index.js b/core/computed/metrics/lantern-speed-index.js index a9cb9c2577ab..94241716b9a0 100644 --- a/core/computed/metrics/lantern-speed-index.js +++ b/core/computed/metrics/lantern-speed-index.js @@ -4,15 +4,15 @@ * SPDX-License-Identifier: Apache-2.0 */ +import * as Lantern from '../../lib/lantern/lantern.js'; import {makeComputedArtifact} from '../computed-artifact.js'; import {getComputationDataParams, lanternErrorAdapter} from './lantern-metric.js'; import {Speedline} from '../speedline.js'; import {LanternFirstContentfulPaint} from './lantern-first-contentful-paint.js'; -import {SpeedIndex} from '../../lib/lantern/metrics/SpeedIndex.js'; /** @typedef {import('../../lib/lantern/Metric.js').Extras} Extras */ -class LanternSpeedIndex extends SpeedIndex { +class LanternSpeedIndex extends Lantern.Metrics.SpeedIndex { /** * @param {LH.Artifacts.MetricComputationDataInput} data * @param {LH.Artifacts.ComputedContext} context diff --git a/core/computed/metrics/lantern-total-blocking-time.js b/core/computed/metrics/lantern-total-blocking-time.js index 8beec3225f03..368d6a40ac74 100644 --- a/core/computed/metrics/lantern-total-blocking-time.js +++ b/core/computed/metrics/lantern-total-blocking-time.js @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import {TotalBlockingTime} from '../../lib/lantern/metrics/TotalBlockingTime.js'; +import * as Lantern from '../../lib/lantern/lantern.js'; import {makeComputedArtifact} from '../computed-artifact.js'; import {LanternFirstContentfulPaint} from './lantern-first-contentful-paint.js'; import {LanternInteractive} from './lantern-interactive.js'; @@ -12,7 +12,7 @@ import {getComputationDataParams} from './lantern-metric.js'; /** @typedef {import('../../lib/lantern/Metric.js').Extras} Extras */ -class LanternTotalBlockingTime extends TotalBlockingTime { +class LanternTotalBlockingTime extends Lantern.Metrics.TotalBlockingTime { /** * @param {LH.Artifacts.MetricComputationDataInput} data * @param {LH.Artifacts.ComputedContext} context diff --git a/core/computed/metrics/total-blocking-time.js b/core/computed/metrics/total-blocking-time.js index b138aab9d5fd..77a21ed43aad 100644 --- a/core/computed/metrics/total-blocking-time.js +++ b/core/computed/metrics/total-blocking-time.js @@ -4,12 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ +import * as Lantern from '../../lib/lantern/lantern.js'; import {makeComputedArtifact} from '../computed-artifact.js'; import ComputedMetric from './metric.js'; import {TraceProcessor} from '../../lib/tracehouse/trace-processor.js'; import {LanternTotalBlockingTime} from './lantern-total-blocking-time.js'; import {Interactive} from './interactive.js'; -import {calculateSumOfBlockingTime} from '../../lib/lantern/TBTUtils.js'; + +const {calculateSumOfBlockingTime} = Lantern.TBTUtils; /** * @fileoverview This audit determines Total Blocking Time. diff --git a/core/computed/network-analysis.js b/core/computed/network-analysis.js index aee4577383ea..a486c7b715cb 100644 --- a/core/computed/network-analysis.js +++ b/core/computed/network-analysis.js @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +import * as Lantern from '../lib/lantern/lantern.js'; import {makeComputedArtifact} from './computed-artifact.js'; -import {NetworkAnalyzer} from '../lib/lantern/simulator/NetworkAnalyzer.js'; import {NetworkRecords} from './network-records.js'; class NetworkAnalysis { @@ -16,7 +16,7 @@ class NetworkAnalysis { */ static async compute_(devtoolsLog, context) { const records = await NetworkRecords.request(devtoolsLog, context); - return NetworkAnalyzer.analyze(records); + return Lantern.Simulation.NetworkAnalyzer.analyze(records); } } diff --git a/core/computed/page-dependency-graph.js b/core/computed/page-dependency-graph.js index 87dc7eaa87f1..061b3354921e 100644 --- a/core/computed/page-dependency-graph.js +++ b/core/computed/page-dependency-graph.js @@ -4,13 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ +import * as Lantern from '../lib/lantern/lantern.js'; import {makeComputedArtifact} from './computed-artifact.js'; -import {PageDependencyGraph as LanternPageDependencyGraph} from '../lib/lantern/PageDependencyGraph.js'; import {NetworkRequest} from '../lib/network-request.js'; import {ProcessedTrace} from './processed-trace.js'; import {NetworkRecords} from './network-records.js'; import {TraceEngineResult} from './trace-engine-result.js'; -import * as TraceEngineComputationData from '../lib/lantern/TraceEngineComputationData.js'; /** @typedef {import('../lib/lantern/BaseNode.js').Node} Node */ @@ -30,14 +29,15 @@ class PageDependencyGraph { if (data.fromTrace) { const traceEngineResult = await TraceEngineResult.request({trace}, context); const traceEngineData = traceEngineResult.data; - const requests = TraceEngineComputationData.createNetworkRequests(trace, traceEngineData); + const requests = + Lantern.TraceEngineComputationData.createNetworkRequests(trace, traceEngineData); const graph = - TraceEngineComputationData.createGraph(requests, trace, traceEngineData, URL); + Lantern.TraceEngineComputationData.createGraph(requests, trace, traceEngineData, URL); return graph; } const lanternRequests = networkRecords.map(NetworkRequest.asLanternNetworkRequest); - return LanternPageDependencyGraph.createGraph(mainThreadEvents, lanternRequests, URL); + return Lantern.PageDependencyGraph.createGraph(mainThreadEvents, lanternRequests, URL); } } diff --git a/core/computed/tbt-impact-tasks.js b/core/computed/tbt-impact-tasks.js index 8310f82430d9..61f0040acfac 100644 --- a/core/computed/tbt-impact-tasks.js +++ b/core/computed/tbt-impact-tasks.js @@ -4,14 +4,15 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as Lantern from '../lib/lantern/types/lantern.js'; +import * as Lantern from '../lib/lantern/lantern.js'; import {makeComputedArtifact} from './computed-artifact.js'; import {MainThreadTasks} from './main-thread-tasks.js'; import {FirstContentfulPaint} from './metrics/first-contentful-paint.js'; import {Interactive} from './metrics/interactive.js'; import {TotalBlockingTime} from './metrics/total-blocking-time.js'; import {ProcessedTrace} from './processed-trace.js'; -import {calculateTbtImpactForEvent} from '../lib/lantern/TBTUtils.js'; + +const {calculateTbtImpactForEvent} = Lantern.TBTUtils; class TBTImpactTasks { /** diff --git a/core/config/constants.js b/core/config/constants.js index 0d8da0a3a4fe..ae886b6fa912 100644 --- a/core/config/constants.js +++ b/core/config/constants.js @@ -6,7 +6,7 @@ import * as Lantern from '../lib/lantern/lantern.js'; -const throttling = Lantern.constants.throttling; +const throttling = Lantern.Simulation.Constants.throttling; /** * @type {Required} diff --git a/core/lib/asset-saver.js b/core/lib/asset-saver.js index ddbc480a3294..55512b49bc05 100644 --- a/core/lib/asset-saver.js +++ b/core/lib/asset-saver.js @@ -12,7 +12,7 @@ import {createGzip, gunzipSync} from 'zlib'; import log from 'lighthouse-logger'; -import {Simulator} from './lantern/simulator/Simulator.js'; +import * as Lantern from './lantern/lantern.js'; import lanternTraceSaver from './lantern-trace-saver.js'; import {MetricTraceEvents} from './traces/metric-trace-events.js'; import {NetworkAnalysis} from '../computed/network-analysis.js'; @@ -449,7 +449,7 @@ function saveDevtoolsLog(devtoolsLog, devtoolLogFilename, options = {}) { async function saveLanternDebugTraces(pathWithBasename) { if (!process.env.LANTERN_DEBUG) return; - for (const [label, nodeTimings] of Simulator.ALL_NODE_TIMINGS) { + for (const [label, nodeTimings] of Lantern.Simulation.Simulator.ALL_NODE_TIMINGS) { if (lanternTraceSaver.simulationNamesToIgnore.includes(label)) continue; const traceFilename = `${pathWithBasename}-${label}${traceSuffix}`; diff --git a/core/lib/lantern-trace-saver.js b/core/lib/lantern-trace-saver.js index 4f469d038d22..a9a10cdd3e5f 100644 --- a/core/lib/lantern-trace-saver.js +++ b/core/lib/lantern-trace-saver.js @@ -5,7 +5,7 @@ */ /** @typedef {import('./lantern/BaseNode.js').Node} Node */ -/** @typedef {import('./lantern/simulator/Simulator.js').CompleteNodeTiming} CompleteNodeTiming */ +/** @typedef {import('./lantern/simulation/Simulator.js').CompleteNodeTiming} CompleteNodeTiming */ /** * @param {Map} nodeTimings diff --git a/core/lib/lantern/BaseNode.js b/core/lib/lantern/BaseNode.js index e2f8beb4ef9d..cecd085c0ff2 100644 --- a/core/lib/lantern/BaseNode.js +++ b/core/lib/lantern/BaseNode.js @@ -28,6 +28,11 @@ * @template [T=any] */ class BaseNode { + static TYPES = /** @type {{NETWORK: 'network', CPU: 'cpu'}} */({ + NETWORK: 'network', + CPU: 'cpu', + }); + /** * @param {string} id */ @@ -361,9 +366,4 @@ class BaseNode { } } -BaseNode.TYPES = /** @type {{NETWORK: 'network', CPU: 'cpu'}} */({ - NETWORK: 'network', - CPU: 'cpu', -}); - export {BaseNode}; diff --git a/core/lib/lantern/CpuNode.js b/core/lib/lantern/CpuNode.js index 9148c1cb7395..749626abf13f 100644 --- a/core/lib/lantern/CpuNode.js +++ b/core/lib/lantern/CpuNode.js @@ -4,14 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as Lantern from './types/lantern.js'; -import {BaseNode} from './BaseNode.js'; +import * as Lantern from './lantern.js'; /** * @template [T=any] - * @extends {BaseNode} + * @extends {Lantern.BaseNode} */ -class CPUNode extends BaseNode { +class CPUNode extends Lantern.BaseNode { /** * @param {Lantern.TraceEvent} parentEvent * @param {Lantern.TraceEvent[]=} childEvents @@ -27,7 +26,7 @@ class CPUNode extends BaseNode { } get type() { - return BaseNode.TYPES.CPU; + return Lantern.BaseNode.TYPES.CPU; } /** diff --git a/core/lib/lantern/Metric.js b/core/lib/lantern/Metric.js index dcb3d5ab5780..e0497b047362 100644 --- a/core/lib/lantern/Metric.js +++ b/core/lib/lantern/Metric.js @@ -4,20 +4,18 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as Lantern from './types/lantern.js'; -import {BaseNode} from './BaseNode.js'; -import {RESOURCE_TYPES} from '../network-request.js'; +import * as Lantern from './lantern.js'; /** @typedef {import('./BaseNode.js').Node} Node */ /** @typedef {import('./NetworkNode.js').NetworkNode} NetworkNode */ -/** @typedef {import('./simulator/Simulator.js').Simulator} Simulator */ +/** @typedef {import('./simulation/Simulator.js').Simulator} Simulator */ /** * @typedef Extras * @property {boolean} optimistic - * @property {Lantern.Metric=} fcpResult - * @property {Lantern.Metric=} lcpResult - * @property {Lantern.Metric=} interactiveResult + * @property {Lantern.Metrics.Result=} fcpResult + * @property {Lantern.Metrics.Result=} lcpResult + * @property {Lantern.Metrics.Result=} interactiveResult * @property {number=} observedSpeedIndex */ @@ -32,8 +30,8 @@ class Metric { const scriptUrls = new Set(); dependencyGraph.traverse(node => { - if (node.type !== BaseNode.TYPES.NETWORK) return; - if (node.request.resourceType !== RESOURCE_TYPES.Script) return; + if (node.type !== Lantern.BaseNode.TYPES.NETWORK) return; + if (node.request.resourceType !== Lantern.NetworkRequestTypes.Script) return; if (treatNodeAsRenderBlocking?.(node)) { scriptUrls.add(node.request.url); } @@ -92,7 +90,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/NetworkNode.js b/core/lib/lantern/NetworkNode.js index d7064d658284..6632726fa5be 100644 --- a/core/lib/lantern/NetworkNode.js +++ b/core/lib/lantern/NetworkNode.js @@ -4,9 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as Lantern from './types/lantern.js'; +import * as Lantern from './lantern.js'; import {NetworkRequestTypes} from './lantern.js'; -import {BaseNode} from './BaseNode.js'; const NON_NETWORK_SCHEMES = [ 'blob', // @see https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL @@ -35,9 +34,9 @@ function isNonNetworkProtocol(protocol) { /** * @template [T=any] - * @extends {BaseNode} + * @extends {Lantern.BaseNode} */ -class NetworkNode extends BaseNode { +class NetworkNode extends Lantern.BaseNode { /** * @param {Lantern.NetworkRequest} networkRequest */ @@ -48,7 +47,7 @@ class NetworkNode extends BaseNode { } get type() { - return BaseNode.TYPES.NETWORK; + return Lantern.BaseNode.TYPES.NETWORK; } /** diff --git a/core/lib/lantern/PageDependencyGraph.js b/core/lib/lantern/PageDependencyGraph.js index f7673cb18b54..b3a7ea609361 100644 --- a/core/lib/lantern/PageDependencyGraph.js +++ b/core/lib/lantern/PageDependencyGraph.js @@ -4,11 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as Lantern from './types/lantern.js'; -import {NetworkRequestTypes} from './lantern.js'; +import * as Lantern from './lantern.js'; import {NetworkNode} from './NetworkNode.js'; import {CPUNode} from './CpuNode.js'; -import {NetworkAnalyzer} from './simulator/NetworkAnalyzer.js'; // COMPAT: m71+ We added RunTask to `disabled-by-default-lighthouse` const SCHEDULABLE_TASK_TITLE_LH = 'RunTask'; @@ -104,7 +102,7 @@ class PageDependencyGraph { // If the request was for the root document of an iframe, save an entry in our // map so we can link up the task `args.data.frame` dependencies later in graph creation. if (request.frameId && - request.resourceType === NetworkRequestTypes.Document && + request.resourceType === Lantern.NetworkRequestTypes.Document && request.documentURL === request.url) { // If there's ever any ambiguity, permanently set the value to `false` to avoid loops in the graph. const value = frameIdToNodeMap.has(request.frameId) ? null : node; @@ -245,7 +243,9 @@ class PageDependencyGraph { static linkCPUNodes(rootNode, networkNodeOutput, cpuNodes) { /** @type {Set} */ const linkableResourceTypes = new Set([ - NetworkRequestTypes.XHR, NetworkRequestTypes.Fetch, NetworkRequestTypes.Script, + Lantern.NetworkRequestTypes.XHR, + Lantern.NetworkRequestTypes.Fetch, + Lantern.NetworkRequestTypes.Script, ]); /** @param {CPUNode} cpuNode @param {string} reqId */ @@ -553,12 +553,13 @@ class PageDependencyGraph { if (!requestedUrl) throw new Error('requestedUrl is required to get the root request'); if (!mainDocumentUrl) throw new Error('mainDocumentUrl is required to get the main resource'); - const rootRequest = NetworkAnalyzer.findResourceForUrl(networkRequests, requestedUrl); + const rootRequest = + Lantern.Simulation.NetworkAnalyzer.findResourceForUrl(networkRequests, requestedUrl); if (!rootRequest) throw new Error('rootRequest not found'); const rootNode = networkNodeOutput.idToNodeMap.get(rootRequest.requestId); if (!rootNode) throw new Error('rootNode not found'); const mainDocumentRequest = - NetworkAnalyzer.findLastDocumentForUrl(networkRequests, mainDocumentUrl); + Lantern.Simulation.NetworkAnalyzer.findLastDocumentForUrl(networkRequests, mainDocumentUrl); if (!mainDocumentRequest) throw new Error('mainDocumentRequest not found'); const mainDocumentNode = networkNodeOutput.idToNodeMap.get(mainDocumentRequest.requestId); if (!mainDocumentNode) throw new Error('mainDocumentNode not found'); diff --git a/core/lib/lantern/TraceEngineComputationData.js b/core/lib/lantern/TraceEngineComputationData.js index ebbec88f7451..6c0450ca7dd3 100644 --- a/core/lib/lantern/TraceEngineComputationData.js +++ b/core/lib/lantern/TraceEngineComputationData.js @@ -7,9 +7,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 './PageDependencyGraph.js'; -import {RESOURCE_TYPES} from '../network-request.js'; +import * as Lantern from './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 */ @@ -232,7 +230,7 @@ function chooseInitiatorRequest(request, requestsByURL) { return request.redirectSource; } - const initiatorURL = PageDependencyGraph.getNetworkInitiators(request)[0]; + const initiatorURL = Lantern.PageDependencyGraph.getNetworkInitiators(request)[0]; let candidates = requestsByURL.get(initiatorURL) || []; // The (valid) initiator must come before the initiated request. candidates = candidates.filter(c => { @@ -243,7 +241,7 @@ function chooseInitiatorRequest(request, requestsByURL) { // Disambiguate based on prefetch. Prefetch requests have type 'Other' and cannot // initiate requests, so we drop them here. const nonPrefetchCandidates = candidates.filter( - cand => cand.resourceType !== RESOURCE_TYPES.Other); + cand => cand.resourceType !== Lantern.NetworkRequestTypes.Other); if (nonPrefetchCandidates.length) { candidates = nonPrefetchCandidates; } @@ -258,7 +256,7 @@ function chooseInitiatorRequest(request, requestsByURL) { if (candidates.length > 1 && request.initiator.type === 'parser') { // Filter to just Documents when initiator type is parser. const documentCandidates = candidates.filter(cand => - cand.resourceType === RESOURCE_TYPES.Document); + cand.resourceType === Lantern.NetworkRequestTypes.Document); if (documentCandidates.length) { candidates = documentCandidates; } @@ -458,7 +456,7 @@ function createGraph(requests, trace, traceEngineData, URL) { URL.mainDocumentUrl = request.url; } - return PageDependencyGraph.createGraph(mainThreadEvents, requests, URL); + return Lantern.PageDependencyGraph.createGraph(mainThreadEvents, requests, URL); } export { diff --git a/core/lib/lantern/lantern.js b/core/lib/lantern/lantern.js index b4c8f2e2fc69..c636c90904c0 100644 --- a/core/lib/lantern/lantern.js +++ b/core/lib/lantern/lantern.js @@ -28,48 +28,24 @@ const NetworkRequestTypes = { Prefetch: 'Prefetch', }; -const DEVTOOLS_RTT_ADJUSTMENT_FACTOR = 3.75; -const DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR = 0.9; +export {BaseNode} from './BaseNode.js'; +export {CPUNode} from './CpuNode.js'; +export {LanternError as Error} from './LanternError.js'; +export {Metric} from './Metric.js'; +export {NetworkNode} from './NetworkNode.js'; +export {PageDependencyGraph} from './PageDependencyGraph.js'; +export * as Metrics from './metrics/metrics.js'; +export * as Simulation from './simulation/simulation.js'; +export * as TBTUtils from './TBTUtils.js'; +export * as TraceEngineComputationData from './TraceEngineComputationData.js'; -const throttling = { - DEVTOOLS_RTT_ADJUSTMENT_FACTOR, - DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR, - // These values align with WebPageTest's definition of "Fast 3G" - // But offer similar characteristics to roughly the 75th percentile of 4G connections. - mobileSlow4G: { - rttMs: 150, - throughputKbps: 1.6 * 1024, - requestLatencyMs: 150 * DEVTOOLS_RTT_ADJUSTMENT_FACTOR, - downloadThroughputKbps: 1.6 * 1024 * DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR, - uploadThroughputKbps: 750 * DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR, - cpuSlowdownMultiplier: 4, - }, - // These values partially align with WebPageTest's definition of "Regular 3G". - // These values are meant to roughly align with Chrome UX report's 3G definition which are based - // on HTTP RTT of 300-1400ms and downlink throughput of <700kbps. - mobileRegular3G: { - rttMs: 300, - throughputKbps: 700, - requestLatencyMs: 300 * DEVTOOLS_RTT_ADJUSTMENT_FACTOR, - downloadThroughputKbps: 700 * DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR, - uploadThroughputKbps: 700 * DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR, - cpuSlowdownMultiplier: 4, - }, - // Using a "broadband" connection type - // Corresponds to "Dense 4G 25th percentile" in https://docs.google.com/document/d/1Ft1Bnq9-t4jK5egLSOc28IL4TvR-Tt0se_1faTA4KTY/edit#heading=h.bb7nfy2x9e5v - desktopDense4G: { - rttMs: 40, - throughputKbps: 10 * 1024, - cpuSlowdownMultiplier: 1, - requestLatencyMs: 0, // 0 means unset - downloadThroughputKbps: 0, - uploadThroughputKbps: 0, - }, -}; - -const constants = {throttling}; +/** @template [T=any] @typedef {Lantern.NetworkRequest} NetworkRequest */ +/** @typedef {Lantern.ResourcePriority} ResourcePriority */ +/** @typedef {Lantern.ResourceTiming} ResourceTiming */ +/** @typedef {Lantern.ResourceType} ResourceType */ +/** @typedef {Lantern.Trace} Trace */ +/** @typedef {Lantern.TraceEvent} TraceEvent */ export { NetworkRequestTypes, - constants, }; diff --git a/core/lib/lantern/metrics/FirstContentfulPaint.js b/core/lib/lantern/metrics/FirstContentfulPaint.js index b0aef22ba742..8c9bbc96afb0 100644 --- a/core/lib/lantern/metrics/FirstContentfulPaint.js +++ b/core/lib/lantern/metrics/FirstContentfulPaint.js @@ -4,15 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as Lantern from '../types/lantern.js'; -import {Metric} from '../Metric.js'; -import {BaseNode} from '../BaseNode.js'; +import * as Lantern from '../lantern.js'; /** @typedef {import('../BaseNode.js').Node} Node */ /** @template T @typedef {import('../NetworkNode.js').NetworkNode} NetworkNode */ /** @typedef {import('../CpuNode.js').CPUNode} CpuNode */ -class FirstContentfulPaint extends Metric { +class FirstContentfulPaint extends Lantern.Metric { /** * @return {Lantern.Simulation.MetricCoefficients} */ @@ -57,7 +55,7 @@ class FirstContentfulPaint extends Metric { /** @type {Array} */ const cpuNodes = []; graph.traverse(node => { - if (node.type === BaseNode.TYPES.CPU) { + if (node.type === Lantern.BaseNode.TYPES.CPU) { // A task is *possibly* render blocking if it *started* before cutoffTimestamp. // We use startTime here because the paint event can be *inside* the task that was render blocking. if (node.startTime <= cutoffTimestamp) cpuNodes.push(node); @@ -75,7 +73,7 @@ class FirstContentfulPaint extends Metric { cpuNodes.sort((a, b) => a.startTime - b.startTime); // A script is *possibly* render blocking if it finished loading before cutoffTimestamp. - const possiblyRenderBlockingScriptUrls = Metric.getScriptUrls(graph, node => { + const possiblyRenderBlockingScriptUrls = Lantern.Metric.getScriptUrls(graph, node => { // The optimistic LCP treatNodeAsRenderBlocking fn wants to exclude some images in the graph, // but here it only receives scripts to evaluate. It's a no-op in this case, but it will // matter below in the getFirstPaintBasedGraph clone operation. @@ -147,7 +145,7 @@ class FirstContentfulPaint extends Metric { const {definitelyNotRenderBlockingScriptUrls, renderBlockingCpuNodeIds} = rbData; return dependencyGraph.cloneWithRelationships(node => { - if (node.type === BaseNode.TYPES.NETWORK) { + if (node.type === Lantern.BaseNode.TYPES.NETWORK) { // Exclude all nodes that ended after cutoffTimestamp (except for the main document which we always consider necessary) // endTime is negative if request does not finish, make sure startTime isn't after cutoffTimestamp in this case. const endedAfterPaint = node.endTime > cutoffTimestamp || node.startTime > cutoffTimestamp; diff --git a/core/lib/lantern/metrics/Interactive.js b/core/lib/lantern/metrics/Interactive.js index e71f4b9e143d..d2244868627e 100644 --- a/core/lib/lantern/metrics/Interactive.js +++ b/core/lib/lantern/metrics/Interactive.js @@ -4,17 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as Lantern from '../types/lantern.js'; -import {Metric} from '../Metric.js'; -import {BaseNode} from '../BaseNode.js'; -import {NetworkRequestTypes} from '../lantern.js'; +import * as Lantern from '../lantern.js'; /** @typedef {import('../BaseNode.js').Node} Node */ // Any CPU task of 20 ms or more will end up being a critical long task on mobile const CRITICAL_LONG_TASK_THRESHOLD = 20; -class Interactive extends Metric { +class Interactive extends Lantern.Metric { /** * @return {Lantern.Simulation.MetricCoefficients} */ @@ -36,13 +33,13 @@ class Interactive extends Metric { return dependencyGraph.cloneWithRelationships(node => { // Include everything that might be a long task - if (node.type === BaseNode.TYPES.CPU) { + if (node.type === Lantern.BaseNode.TYPES.CPU) { return node.duration > minimumCpuTaskDuration; } // Include all scripts and high priority requests, exclude all images - const isImage = node.request.resourceType === NetworkRequestTypes.Image; - const isScript = node.request.resourceType === NetworkRequestTypes.Script; + const isImage = node.request.resourceType === Lantern.NetworkRequestTypes.Image; + const isScript = node.request.resourceType === Lantern.NetworkRequestTypes.Script; return ( !isImage && (isScript || @@ -81,7 +78,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; @@ -101,7 +98,7 @@ class Interactive extends Metric { static getLastLongTaskEndTime(nodeTimings, duration = 50) { return Array.from(nodeTimings.entries()) .filter(([node, timing]) => { - if (node.type !== BaseNode.TYPES.CPU) return false; + if (node.type !== Lantern.BaseNode.TYPES.CPU) return false; return timing.duration > duration; }) .map(([_, timing]) => timing.endTime) diff --git a/core/lib/lantern/metrics/LargestContentfulPaint.js b/core/lib/lantern/metrics/LargestContentfulPaint.js index 061a5fd274a8..3efa9a507021 100644 --- a/core/lib/lantern/metrics/LargestContentfulPaint.js +++ b/core/lib/lantern/metrics/LargestContentfulPaint.js @@ -4,14 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as Lantern from '../types/lantern.js'; -import {Metric} from '../Metric.js'; -import {FirstContentfulPaint} from './FirstContentfulPaint.js'; -import {LanternError} from '../LanternError.js'; +import * as Lantern from '../lantern.js'; /** @typedef {import('../BaseNode.js').Node} Node */ -class LargestContentfulPaint extends Metric { +class LargestContentfulPaint extends Lantern.Metric { /** * @return {Lantern.Simulation.MetricCoefficients} */ @@ -45,10 +42,10 @@ class LargestContentfulPaint extends Metric { static getOptimisticGraph(dependencyGraph, processedNavigation) { const lcp = processedNavigation.timestamps.largestContentfulPaint; if (!lcp) { - throw new LanternError('NO_LCP'); + throw new Lantern.Error('NO_LCP'); } - return FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, { + return Lantern.Metrics.FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, { cutoffTimestamp: lcp, treatNodeAsRenderBlocking: LargestContentfulPaint.isNotLowPriorityImageNode, }); @@ -62,10 +59,10 @@ class LargestContentfulPaint extends Metric { static getPessimisticGraph(dependencyGraph, processedNavigation) { const lcp = processedNavigation.timestamps.largestContentfulPaint; if (!lcp) { - throw new LanternError('NO_LCP'); + throw new Lantern.Error('NO_LCP'); } - return FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, { + return Lantern.Metrics.FirstContentfulPaint.getFirstPaintBasedGraph(dependencyGraph, { cutoffTimestamp: lcp, treatNodeAsRenderBlocking: _ => true, // For pessimistic LCP we'll include *all* layout nodes @@ -91,7 +88,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/MaxPotentialFID.js b/core/lib/lantern/metrics/MaxPotentialFID.js index 334ce434950a..83bf3b06c807 100644 --- a/core/lib/lantern/metrics/MaxPotentialFID.js +++ b/core/lib/lantern/metrics/MaxPotentialFID.js @@ -4,13 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as Lantern from '../types/lantern.js'; -import {Metric} from '../Metric.js'; -import {BaseNode} from '../BaseNode.js'; +import * as Lantern from '../lantern.js'; /** @typedef {import('../BaseNode.js').Node} Node */ -class MaxPotentialFID extends Metric { +class MaxPotentialFID extends Lantern.Metric { /** * @return {Lantern.Simulation.MetricCoefficients} */ @@ -66,7 +64,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; @@ -84,7 +82,8 @@ class MaxPotentialFID extends Metric { */ static getTimingsAfterFCP(nodeTimings, fcpTimeInMs) { return Array.from(nodeTimings.entries()) - .filter(([node, timing]) => node.type === BaseNode.TYPES.CPU && timing.endTime > fcpTimeInMs) + .filter(([node, timing]) => + node.type === Lantern.BaseNode.TYPES.CPU && timing.endTime > fcpTimeInMs) .map(([_, timing]) => timing); } } diff --git a/core/lib/lantern/metrics/SpeedIndex.js b/core/lib/lantern/metrics/SpeedIndex.js index 8a77c2a9937f..9fdbd173a522 100644 --- a/core/lib/lantern/metrics/SpeedIndex.js +++ b/core/lib/lantern/metrics/SpeedIndex.js @@ -4,15 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as Lantern from '../types/lantern.js'; -import {Metric} from '../Metric.js'; -import {BaseNode} from '../BaseNode.js'; +import * as Lantern from '../lantern.js'; const mobileSlow4GRtt = 150; /** @typedef {import('../BaseNode.js').Node} Node */ -class SpeedIndex extends Metric { +class SpeedIndex extends Lantern.Metric { /** * @return {Lantern.Simulation.MetricCoefficients} */ @@ -91,7 +89,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; @@ -123,7 +121,7 @@ class SpeedIndex extends Metric { /** @type {Array<{time: number, weight: number}>} */ const layoutWeights = []; for (const [node, timing] of nodeTimings.entries()) { - if (node.type !== BaseNode.TYPES.CPU) continue; + if (node.type !== Lantern.BaseNode.TYPES.CPU) continue; if (node.childEvents.some(x => x.name === 'Layout')) { const timingWeight = Math.max(Math.log2(timing.endTime - timing.startTime), 0); diff --git a/core/lib/lantern/metrics/TotalBlockingTime.js b/core/lib/lantern/metrics/TotalBlockingTime.js index 314a39863158..6e94d88265a4 100644 --- a/core/lib/lantern/metrics/TotalBlockingTime.js +++ b/core/lib/lantern/metrics/TotalBlockingTime.js @@ -4,14 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as Lantern from '../types/lantern.js'; -import {Metric} from '../Metric.js'; -import {BaseNode} from '../BaseNode.js'; -import {BLOCKING_TIME_THRESHOLD, calculateSumOfBlockingTime} from '../TBTUtils.js'; +import * as Lantern from '../lantern.js'; /** @typedef {import('../BaseNode.js').Node} Node */ -class TotalBlockingTime extends Metric { +class TotalBlockingTime extends Lantern.Metric { /** * @return {Lantern.Simulation.MetricCoefficients} */ @@ -64,7 +61,7 @@ class TotalBlockingTime extends Metric { ? extras.interactiveResult.optimisticEstimate.timeInMs : extras.interactiveResult.pessimisticEstimate.timeInMs; - const minDurationMs = BLOCKING_TIME_THRESHOLD; + const minDurationMs = Lantern.TBTUtils.BLOCKING_TIME_THRESHOLD; const events = TotalBlockingTime.getTopLevelEvents( simulation.nodeTimings, @@ -72,7 +69,7 @@ class TotalBlockingTime extends Metric { ); return { - timeInMs: calculateSumOfBlockingTime( + timeInMs: Lantern.TBTUtils.calculateSumOfBlockingTime( events, fcpTimeInMs, interactiveTimeMs @@ -84,7 +81,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; @@ -110,7 +107,7 @@ class TotalBlockingTime extends Metric { const events = []; for (const [node, timing] of nodeTimings.entries()) { - if (node.type !== BaseNode.TYPES.CPU) continue; + if (node.type !== Lantern.BaseNode.TYPES.CPU) continue; // Filtering out events below minimum duration. if (timing.duration < minDurationMs) continue; diff --git a/core/lib/lantern/metrics/metrics.js b/core/lib/lantern/metrics/metrics.js new file mode 100644 index 000000000000..e8d20b4ad2a7 --- /dev/null +++ b/core/lib/lantern/metrics/metrics.js @@ -0,0 +1,16 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as Lantern from '../types/lantern.js'; + +export {FirstContentfulPaint} from './FirstContentfulPaint.js'; +export {Interactive} from './Interactive.js'; +export {LargestContentfulPaint} from './LargestContentfulPaint.js'; +export {MaxPotentialFID} from './MaxPotentialFID.js'; +export {SpeedIndex} from './SpeedIndex.js'; +export {TotalBlockingTime} from './TotalBlockingTime.js'; + +/** @template [T=any] @typedef {Lantern.MetricResult} Result */ diff --git a/core/lib/lantern/simulator/ConnectionPool.js b/core/lib/lantern/simulation/ConnectionPool.js similarity index 99% rename from core/lib/lantern/simulator/ConnectionPool.js rename to core/lib/lantern/simulation/ConnectionPool.js index 86b1134ec808..f08f92147a64 100644 --- a/core/lib/lantern/simulator/ConnectionPool.js +++ b/core/lib/lantern/simulation/ConnectionPool.js @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as Lantern from '../types/lantern.js'; +import * as Lantern from '../lantern.js'; import {NetworkAnalyzer} from './NetworkAnalyzer.js'; import {TcpConnection} from './TcpConnection.js'; diff --git a/core/lib/lantern/simulation/Constants.js b/core/lib/lantern/simulation/Constants.js new file mode 100644 index 000000000000..ecbb5ab83533 --- /dev/null +++ b/core/lib/lantern/simulation/Constants.js @@ -0,0 +1,48 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +const DEVTOOLS_RTT_ADJUSTMENT_FACTOR = 3.75; +const DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR = 0.9; + +const throttling = { + DEVTOOLS_RTT_ADJUSTMENT_FACTOR, + DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR, + // These values align with WebPageTest's definition of "Fast 3G" + // But offer similar characteristics to roughly the 75th percentile of 4G connections. + mobileSlow4G: { + rttMs: 150, + throughputKbps: 1.6 * 1024, + requestLatencyMs: 150 * DEVTOOLS_RTT_ADJUSTMENT_FACTOR, + downloadThroughputKbps: 1.6 * 1024 * DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR, + uploadThroughputKbps: 750 * DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR, + cpuSlowdownMultiplier: 4, + }, + // These values partially align with WebPageTest's definition of "Regular 3G". + // These values are meant to roughly align with Chrome UX report's 3G definition which are based + // on HTTP RTT of 300-1400ms and downlink throughput of <700kbps. + mobileRegular3G: { + rttMs: 300, + throughputKbps: 700, + requestLatencyMs: 300 * DEVTOOLS_RTT_ADJUSTMENT_FACTOR, + downloadThroughputKbps: 700 * DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR, + uploadThroughputKbps: 700 * DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR, + cpuSlowdownMultiplier: 4, + }, + // Using a "broadband" connection type + // Corresponds to "Dense 4G 25th percentile" in https://docs.google.com/document/d/1Ft1Bnq9-t4jK5egLSOc28IL4TvR-Tt0se_1faTA4KTY/edit#heading=h.bb7nfy2x9e5v + desktopDense4G: { + rttMs: 40, + throughputKbps: 10 * 1024, + cpuSlowdownMultiplier: 1, + requestLatencyMs: 0, // 0 means unset + downloadThroughputKbps: 0, + uploadThroughputKbps: 0, + }, +}; + +const Constants = {throttling}; + +export {Constants}; diff --git a/core/lib/lantern/simulator/DNSCache.js b/core/lib/lantern/simulation/DNSCache.js similarity index 98% rename from core/lib/lantern/simulator/DNSCache.js rename to core/lib/lantern/simulation/DNSCache.js index 2598d7038514..f1d9d2347cbc 100644 --- a/core/lib/lantern/simulator/DNSCache.js +++ b/core/lib/lantern/simulation/DNSCache.js @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as Lantern from '../types/lantern.js'; +import * as Lantern from '../lantern.js'; // A DNS lookup will usually take ~1-2 roundtrips of connection latency plus the extra DNS routing time. // Example: https://www.webpagetest.org/result/180703_3A_e33ec79747c002ed4d7bcbfc81462203/1/details/#waterfall_view_step1 diff --git a/core/lib/lantern/simulator/NetworkAnalyzer.js b/core/lib/lantern/simulation/NetworkAnalyzer.js similarity index 99% rename from core/lib/lantern/simulator/NetworkAnalyzer.js rename to core/lib/lantern/simulation/NetworkAnalyzer.js index 5207658faeae..667a5d4f29a2 100644 --- a/core/lib/lantern/simulator/NetworkAnalyzer.js +++ b/core/lib/lantern/simulation/NetworkAnalyzer.js @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as Lantern from '../types/lantern.js'; +import * as Lantern from '../lantern.js'; import UrlUtils from '../../url-utils.js'; const INITIAL_CWD = 14 * 1024; diff --git a/core/lib/lantern/simulator/SimulationTimingMap.js b/core/lib/lantern/simulation/SimulationTimingMap.js similarity index 98% rename from core/lib/lantern/simulator/SimulationTimingMap.js rename to core/lib/lantern/simulation/SimulationTimingMap.js index 3dea62ec7a1f..4050e2d66b83 100644 --- a/core/lib/lantern/simulator/SimulationTimingMap.js +++ b/core/lib/lantern/simulation/SimulationTimingMap.js @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import {BaseNode} from '../BaseNode.js'; +import * as Lantern from '../lantern.js'; /** * @fileoverview @@ -14,7 +14,6 @@ import {BaseNode} from '../BaseNode.js'; * as nodes are queued, partially simulated, and completed. */ - /** @typedef {import('../BaseNode.js').Node} Node */ /** @typedef {import('../NetworkNode.js').NetworkNode} NetworkNode */ /** @typedef {import('../CpuNode.js').CPUNode} CpuNode */ @@ -83,7 +82,7 @@ class SimulatorTimingMap { this._nodeTimings.set( node, - node.type === BaseNode.TYPES.NETWORK + node.type === Lantern.BaseNode.TYPES.NETWORK ? {...nodeTiming, timeElapsedOvershoot: 0, bytesDownloaded: 0} : nodeTiming ); diff --git a/core/lib/lantern/simulator/Simulator.js b/core/lib/lantern/simulation/Simulator.js similarity index 95% rename from core/lib/lantern/simulator/Simulator.js rename to core/lib/lantern/simulation/Simulator.js index 6b382a241e86..48258f18265a 100644 --- a/core/lib/lantern/simulator/Simulator.js +++ b/core/lib/lantern/simulation/Simulator.js @@ -4,15 +4,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as Lantern from '../types/lantern.js'; -import {BaseNode} from '../BaseNode.js'; +import * as Lantern from '../lantern.js'; import {TcpConnection} from './TcpConnection.js'; import {ConnectionPool} from './ConnectionPool.js'; import {DNSCache} from './DNSCache.js'; import {SimulatorTimingMap} from './SimulationTimingMap.js'; -import {constants} from '../lantern.js'; -const defaultThrottling = constants.throttling.mobileSlow4G; +const Constants = Lantern.Simulation.Constants; +const defaultThrottling = Constants.throttling.mobileSlow4G; /** @typedef {import('../BaseNode.js').Node} Node */ /** @typedef {import('../NetworkNode.js').NetworkNode} NetworkNode */ @@ -82,10 +81,10 @@ class Simulator { case 'devtools': if (throttling) { options.rtt = - throttling.requestLatencyMs / constants.throttling.DEVTOOLS_RTT_ADJUSTMENT_FACTOR; + throttling.requestLatencyMs / Constants.throttling.DEVTOOLS_RTT_ADJUSTMENT_FACTOR; options.throughput = throttling.downloadThroughputKbps * 1024 / - constants.throttling.DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR; + Constants.throttling.DEVTOOLS_THROUGHPUT_ADJUSTMENT_FACTOR; } options.cpuSlowdownMultiplier = 1; @@ -162,7 +161,7 @@ class Simulator { /** @type {Lantern.NetworkRequest[]} */ const records = []; graph.getRootNode().traverse(node => { - if (node.type === BaseNode.TYPES.NETWORK) { + if (node.type === Lantern.BaseNode.TYPES.NETWORK) { records.push(node.request); } }); @@ -268,7 +267,7 @@ class Simulator { * @param {number} totalElapsedTime */ _startNodeIfPossible(node, totalElapsedTime) { - if (node.type === BaseNode.TYPES.CPU) { + if (node.type === Lantern.BaseNode.TYPES.CPU) { // Start a CPU task if there's no other CPU task in process if (this._numberInProgress(node.type) === 0) { this._markNodeAsInProgress(node, totalElapsedTime); @@ -277,7 +276,7 @@ class Simulator { return; } - if (node.type !== BaseNode.TYPES.NETWORK) throw new Error('Unsupported'); + if (node.type !== Lantern.BaseNode.TYPES.NETWORK) throw new Error('Unsupported'); // If a network request is connectionless, we can always start it, so skip the connection checks if (!node.isConnectionless) { @@ -296,7 +295,7 @@ class Simulator { * currently in flight. */ _updateNetworkCapacity() { - const inFlight = this._numberInProgress(BaseNode.TYPES.NETWORK); + const inFlight = this._numberInProgress(Lantern.BaseNode.TYPES.NETWORK); if (inFlight === 0) return; for (const connection of this._connectionPool.connectionsInUse()) { @@ -310,9 +309,9 @@ class Simulator { * @return {number} */ _estimateTimeRemaining(node) { - if (node.type === BaseNode.TYPES.CPU) { + if (node.type === Lantern.BaseNode.TYPES.CPU) { return this._estimateCPUTimeRemaining(node); - } else if (node.type === BaseNode.TYPES.NETWORK) { + } else if (node.type === Lantern.BaseNode.TYPES.NETWORK) { return this._estimateNetworkTimeRemaining(node); } else { throw new Error('Unsupported'); @@ -401,13 +400,13 @@ class Simulator { const timingData = this._nodeTimings.getInProgress(node); const isFinished = timingData.estimatedTimeElapsed === timePeriodLength; - if (node.type === BaseNode.TYPES.CPU || node.isConnectionless) { + if (node.type === Lantern.BaseNode.TYPES.CPU || node.isConnectionless) { return isFinished ? this._markNodeAsComplete(node, totalElapsedTime) : (timingData.timeElapsed += timePeriodLength); } - if (node.type !== BaseNode.TYPES.NETWORK) throw new Error('Unsupported'); + if (node.type !== Lantern.BaseNode.TYPES.NETWORK) throw new Error('Unsupported'); if (!('bytesDownloaded' in timingData)) throw new Error('Invalid timing data'); const request = node.request; @@ -488,7 +487,7 @@ class Simulator { * @return {Lantern.Simulation.Result} */ simulate(graph, options) { - if (BaseNode.hasCycle(graph)) { + if (Lantern.BaseNode.hasCycle(graph)) { throw new Error('Cannot simulate graph with cycle'); } diff --git a/core/lib/lantern/simulator/TcpConnection.js b/core/lib/lantern/simulation/TcpConnection.js similarity index 100% rename from core/lib/lantern/simulator/TcpConnection.js rename to core/lib/lantern/simulation/TcpConnection.js diff --git a/core/lib/lantern/simulation/simulation.js b/core/lib/lantern/simulation/simulation.js new file mode 100644 index 000000000000..6fa461ad199e --- /dev/null +++ b/core/lib/lantern/simulation/simulation.js @@ -0,0 +1,28 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as Lantern from '../types/lantern.js'; + +export {ConnectionPool} from './ConnectionPool.js'; +export {Constants} from './Constants.js'; +export {DNSCache} from './DNSCache.js'; +export {NetworkAnalyzer} from './NetworkAnalyzer.js'; +export {Simulator} from './Simulator.js'; +export {SimulatorTimingMap} from './SimulationTimingMap.js'; +export {TcpConnection} from './TcpConnection.js'; + +/** @template [T=any] @typedef {Lantern.Simulation.GraphNetworkNode} GraphNetworkNode */ +/** @template [T=any] @typedef {Lantern.Simulation.GraphNode} GraphNode */ +/** @template [T=any] @typedef {Lantern.Simulation.Result} Result */ +/** @typedef {Lantern.Simulation.GraphCPUNode} GraphCPUNode */ +/** @typedef {Lantern.Simulation.MetricCoefficients} MetricCoefficients */ +/** @typedef {Lantern.Simulation.MetricComputationDataInput} MetricComputationDataInput */ +/** @typedef {Lantern.Simulation.NodeTiming} NodeTiming */ +/** @typedef {Lantern.Simulation.Options} Options */ +/** @typedef {Lantern.Simulation.PrecomputedLanternData} PrecomputedLanternData */ +/** @typedef {Lantern.Simulation.ProcessedNavigation} ProcessedNavigation */ +/** @typedef {Lantern.Simulation.Settings} Settings */ +/** @typedef {Lantern.Simulation.URL} URL */ diff --git a/core/lib/lantern/types/lantern.d.ts b/core/lib/lantern/types/lantern.d.ts index 1e03650909b4..a29b53cb608c 100644 --- a/core/lib/lantern/types/lantern.d.ts +++ b/core/lib/lantern/types/lantern.d.ts @@ -153,7 +153,7 @@ export class NetworkRequest { fromWorker: boolean; } -interface Metric { +interface MetricResult { timing: number; timestamp?: never; optimisticEstimate: Simulation.Result; @@ -173,7 +173,7 @@ export namespace Simulation { type GraphNode = import('../BaseNode.js').Node; type GraphNetworkNode = import('../NetworkNode.js').NetworkNode; type GraphCPUNode = import('../CpuNode.js').CPUNode; - type Simulator = import('../simulator/Simulator.js').Simulator; + type Simulator = import('../simulation/Simulator.js').Simulator; interface MetricCoefficients { intercept: number; diff --git a/core/lib/navigation-error.js b/core/lib/navigation-error.js index 90de19d8e744..6d55d41e8c3f 100644 --- a/core/lib/navigation-error.js +++ b/core/lib/navigation-error.js @@ -4,8 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +import * as Lantern from './lantern/lantern.js'; import {LighthouseError} from './lh-error.js'; -import {NetworkAnalyzer} from './lantern/simulator/NetworkAnalyzer.js'; import {NetworkRequest} from './network-request.js'; import * as i18n from '../lib/i18n/i18n.js'; @@ -131,7 +131,7 @@ function getNonHtmlError(finalRecord) { function getPageLoadError(navigationError, context) { const {url, networkRecords} = context; /** @type {LH.Artifacts.NetworkRequest|undefined} */ - let mainRecord = NetworkAnalyzer.findResourceForUrl(networkRecords, url); + let mainRecord = Lantern.Simulation.NetworkAnalyzer.findResourceForUrl(networkRecords, url); // If the url doesn't give us a network request, it's possible we landed on a chrome-error:// page // In this case, just get the first document request. @@ -149,7 +149,7 @@ function getPageLoadError(navigationError, context) { // MIME Type is only set on the final redirected document request. Use this for the HTML check instead of root. let finalRecord; if (mainRecord) { - finalRecord = NetworkAnalyzer.resolveRedirects(mainRecord); + finalRecord = Lantern.Simulation.NetworkAnalyzer.resolveRedirects(mainRecord); } else { // We have no network requests to process, use the navError return navigationError; diff --git a/core/lib/network-recorder.js b/core/lib/network-recorder.js index 99514e6ca583..bbd2f50d9858 100644 --- a/core/lib/network-recorder.js +++ b/core/lib/network-recorder.js @@ -9,8 +9,8 @@ import {EventEmitter} from 'events'; import log from 'lighthouse-logger'; import * as LH from '../../types/lh.js'; +import * as Lantern from './lantern/lantern.js'; import {NetworkRequest} from './network-request.js'; -import {PageDependencyGraph} from './lantern/PageDependencyGraph.js'; /** * @typedef {{ @@ -253,7 +253,7 @@ class NetworkRecorder extends RequestEventEmitter { return record.redirectSource; } - const initiatorURL = PageDependencyGraph.getNetworkInitiators(record)[0]; + const initiatorURL = Lantern.PageDependencyGraph.getNetworkInitiators(record)[0]; let candidates = recordsByURL.get(initiatorURL) || []; // The (valid) initiator must come before the initiated request. candidates = candidates.filter(c => { diff --git a/core/lib/network-request.js b/core/lib/network-request.js index 60f8f639d181..1b971691e82e 100644 --- a/core/lib/network-request.js +++ b/core/lib/network-request.js @@ -53,7 +53,7 @@ */ import * as LH from '../../types/lh.js'; -import * as Lantern from './lantern/types/lantern.js'; +import * as Lantern from './lantern/lantern.js'; import UrlUtils from './url-utils.js'; // Lightrider X-Header names for timing information. diff --git a/core/scripts/lantern/run-once.js b/core/scripts/lantern/run-once.js index e7d872411c33..3f0bc767b001 100755 --- a/core/scripts/lantern/run-once.js +++ b/core/scripts/lantern/run-once.js @@ -8,8 +8,8 @@ import fs from 'fs'; import path from 'path'; +import * as Lantern from '../../lib/lantern/lantern.js'; import PredictivePerf from '../../audits/predictive-perf.js'; -import {Simulator} from '../../lib/lantern/simulator/Simulator.js'; import traceSaver from '../../lib/lantern-trace-saver.js'; import {LH_ROOT} from '../../../shared/root.js'; import {readJson} from '../../test/test-utils.js'; @@ -42,7 +42,8 @@ async function run() { process.stdout.write(JSON.stringify(result.details.items[0], null, 2)); // Dump the TTI graph with simulated timings to a trace if LANTERN_DEBUG is enabled - const pessimisticTTINodeTimings = Simulator.ALL_NODE_TIMINGS.get('pessimisticInteractive'); + const pessimisticTTINodeTimings = + Lantern.Simulation.Simulator.ALL_NODE_TIMINGS.get('pessimisticInteractive'); if (process.env.LANTERN_DEBUG && pessimisticTTINodeTimings) { const outputTraceFile = path.basename(tracePath).replace(/.trace.json$/, '.lantern.trace.json'); const outputTracePath = path.join(LH_ROOT, '.tmp', outputTraceFile); diff --git a/core/test/audits/byte-efficiency/byte-efficiency-audit-test.js b/core/test/audits/byte-efficiency/byte-efficiency-audit-test.js index f5fc71e19e79..c450a20f4c1d 100644 --- a/core/test/audits/byte-efficiency/byte-efficiency-audit-test.js +++ b/core/test/audits/byte-efficiency/byte-efficiency-audit-test.js @@ -6,8 +6,8 @@ import assert from 'assert/strict'; +import * as Lantern from '../../../lib/lantern/lantern.js'; import {ByteEfficiencyAudit as ByteEfficiencyAudit_} from '../../../audits/byte-efficiency/byte-efficiency-audit.js'; -import {Simulator} from '../../../lib/lantern/simulator/Simulator.js'; import {LoadSimulator} from '../../../computed/load-simulator.js'; import {getURLArtifactFromDevtoolsLog, readJson} from '../../test-utils.js'; import {networkRecordsToDevtoolsLog} from '../../network-records-to-devtools-log.js'; @@ -83,7 +83,7 @@ describe('Byte efficiency base audit', () => { settings: JSON.parse(JSON.stringify(defaultSettings)), }; - simulator = new Simulator({}); + simulator = new Lantern.Simulation.Simulator({}); }); const baseHeadings = [ diff --git a/core/test/audits/byte-efficiency/render-blocking-resources-test.js b/core/test/audits/byte-efficiency/render-blocking-resources-test.js index 54f2e3c3a823..f83e73c76bb7 100644 --- a/core/test/audits/byte-efficiency/render-blocking-resources-test.js +++ b/core/test/audits/byte-efficiency/render-blocking-resources-test.js @@ -8,12 +8,13 @@ import assert from 'assert/strict'; import RenderBlockingResourcesAudit from '../../../audits/byte-efficiency/render-blocking-resources.js'; // eslint-disable-line max-len import * as constants from '../../../config/constants.js'; -import {NetworkNode} from '../../../lib/lantern/NetworkNode.js'; -import {CPUNode} from '../../../lib/lantern/CpuNode.js'; -import {Simulator} from '../../../lib/lantern/simulator/Simulator.js'; +import * as Lantern from '../../../lib/lantern/lantern.js'; import {NetworkRequest} from '../../../lib/network-request.js'; import {getURLArtifactFromDevtoolsLog, readJson} from '../../test-utils.js'; +const {NetworkNode, CPUNode} = Lantern; +const {Simulator} = Lantern.Simulation; + const trace = readJson('../../fixtures/artifacts/render-blocking/trace.json', import.meta); const devtoolsLog = readJson('../../fixtures/artifacts/render-blocking/devtoolslog.json', import.meta); diff --git a/core/test/computed/load-simulator-test.js b/core/test/computed/load-simulator-test.js index 683a0fdafeed..d2e1a2ecd574 100644 --- a/core/test/computed/load-simulator-test.js +++ b/core/test/computed/load-simulator-test.js @@ -6,8 +6,8 @@ import assert from 'assert/strict'; +import * as Lantern from '../../lib/lantern/lantern.js'; import {LoadSimulator} from '../../computed/load-simulator.js'; -import {NetworkNode} from '../../lib/lantern/NetworkNode.js'; import {NetworkRequest} from '../../lib/network-request.js'; import {readJson} from '../test-utils.js'; @@ -19,7 +19,7 @@ function createNetworkNode() { protocol: 'http', parsedURL: {scheme: 'http', securityOrigin: 'https://pwa.rocks'}, }; - return new NetworkNode(NetworkRequest.asLanternNetworkRequest(record)); + return new Lantern.NetworkNode(NetworkRequest.asLanternNetworkRequest(record)); } describe('Simulator artifact', () => { diff --git a/core/test/computed/page-dependency-graph-test.js b/core/test/computed/page-dependency-graph-test.js index 247cc88a4fd3..1bc719c3c568 100644 --- a/core/test/computed/page-dependency-graph-test.js +++ b/core/test/computed/page-dependency-graph-test.js @@ -6,8 +6,8 @@ import assert from 'assert/strict'; +import * as Lantern from '../../lib/lantern/lantern.js'; import {PageDependencyGraph} from '../../computed/page-dependency-graph.js'; -import {BaseNode} from '../../lib/lantern/BaseNode.js'; import {getURLArtifactFromDevtoolsLog, readJson} from '../test-utils.js'; const sampleTrace = readJson('../fixtures/artifacts/iframe/trace.json', import.meta); @@ -22,7 +22,7 @@ describe('PageDependencyGraph computed artifact', () => { devtoolsLog: sampleDevtoolsLog, URL: getURLArtifactFromDevtoolsLog(sampleDevtoolsLog), }, context); - assert.ok(output instanceof BaseNode, 'did not return a graph'); + assert.ok(output instanceof Lantern.BaseNode, 'did not return a graph'); const dependents = output.getDependents(); const nodeWithNestedDependents = dependents.find(node => node.getDependents().length); assert.ok(nodeWithNestedDependents, 'did not link initiators'); diff --git a/core/test/lib/lantern/base-node-test.js b/core/test/lib/lantern/base-node-test.js index b903ce6256bf..f8457e693e87 100644 --- a/core/test/lib/lantern/base-node-test.js +++ b/core/test/lib/lantern/base-node-test.js @@ -6,8 +6,9 @@ import assert from 'assert/strict'; -import {BaseNode} from '../../../lib/lantern/BaseNode.js'; -import {NetworkNode} from '../../../lib/lantern/NetworkNode.js'; +import * as Lantern from '../../../lib/lantern/lantern.js'; + +const {BaseNode, NetworkNode} = Lantern; function sortedById(nodeArray) { return nodeArray.sort((node1, node2) => node1.id.localeCompare(node2.id)); diff --git a/core/test/lib/lantern/metrics/MetricTestUtils.js b/core/test/lib/lantern/metrics/MetricTestUtils.js index ac31797ec0fb..c6a03ab5a520 100644 --- a/core/test/lib/lantern/metrics/MetricTestUtils.js +++ b/core/test/lib/lantern/metrics/MetricTestUtils.js @@ -6,10 +6,7 @@ import * as TraceEngine from '@paulirish/trace_engine'; -import * as Lantern from '../../../../lib/lantern/types/lantern.js'; -import {NetworkAnalyzer} from '../../../../lib/lantern/simulator/NetworkAnalyzer.js'; -import {Simulator} from '../../../../lib/lantern/simulator/Simulator.js'; -import * as TraceEngineComputationData from '../../../../lib/lantern/TraceEngineComputationData.js'; +import * as Lantern from '../../../../lib/lantern/lantern.js'; import {polyfillDOMRect} from '../../../../lib/polyfill-dom-rect.js'; polyfillDOMRect(); @@ -33,13 +30,15 @@ async function getComputationDataFromFixture({trace, settings, URL}) { const traceEngineData = await runTraceEngine( /** @type {TraceEngine.Types.TraceEvents.TraceEventData[]} */ (trace.traceEvents) ); - const requests = TraceEngineComputationData.createNetworkRequests(trace, traceEngineData); - const networkAnalysis = NetworkAnalyzer.analyze(requests); + const requests = + Lantern.TraceEngineComputationData.createNetworkRequests(trace, traceEngineData); + const networkAnalysis = Lantern.Simulation.NetworkAnalyzer.analyze(requests); return { - simulator: Simulator.createSimulator({...settings, networkAnalysis}), - graph: TraceEngineComputationData.createGraph(requests, trace, traceEngineData, URL), - processedNavigation: TraceEngineComputationData.createProcessedNavigation(traceEngineData), + simulator: Lantern.Simulation.Simulator.createSimulator({...settings, networkAnalysis}), + graph: Lantern.TraceEngineComputationData.createGraph(requests, trace, traceEngineData, URL), + processedNavigation: + Lantern.TraceEngineComputationData.createProcessedNavigation(traceEngineData), }; } diff --git a/core/test/lib/lantern/metrics/first-contentful-paint-test.js b/core/test/lib/lantern/metrics/first-contentful-paint-test.js index a8529bc38507..5e91642edf12 100644 --- a/core/test/lib/lantern/metrics/first-contentful-paint-test.js +++ b/core/test/lib/lantern/metrics/first-contentful-paint-test.js @@ -6,10 +6,12 @@ import assert from 'assert/strict'; -import {FirstContentfulPaint} from '../../../../lib/lantern/metrics/FirstContentfulPaint.js'; +import * as Lantern from '../../../../lib/lantern/lantern.js'; import {readJson} from '../../../test-utils.js'; import {getComputationDataFromFixture} from './MetricTestUtils.js'; +const {FirstContentfulPaint} = Lantern.Metrics; + const trace = readJson('../../../fixtures/artifacts/progressive-app/trace.json', import.meta); describe('Metrics: Lantern FCP', () => { diff --git a/core/test/lib/lantern/metrics/interactive-test.js b/core/test/lib/lantern/metrics/interactive-test.js index befc593db9c8..742c6f9f3d15 100644 --- a/core/test/lib/lantern/metrics/interactive-test.js +++ b/core/test/lib/lantern/metrics/interactive-test.js @@ -6,12 +6,12 @@ import assert from 'assert/strict'; -import {Interactive} from '../../../../lib/lantern/metrics/Interactive.js'; -import {FirstContentfulPaint} from '../../../../lib/lantern/metrics/FirstContentfulPaint.js'; -import {LargestContentfulPaint} from '../../../../lib/lantern/metrics/LargestContentfulPaint.js'; +import * as Lantern from '../../../../lib/lantern/lantern.js'; import {getComputationDataFromFixture} from './MetricTestUtils.js'; import {readJson} from '../../../test-utils.js'; +const {Interactive, FirstContentfulPaint, LargestContentfulPaint} = Lantern.Metrics; + const trace = readJson('../../../fixtures/artifacts/progressive-app/trace.json', import.meta); const iframeTrace = readJson('../../../fixtures/artifacts/iframe/trace.json', import.meta); diff --git a/core/test/lib/lantern/metrics/lantern-largest-contentful-paint-test.js b/core/test/lib/lantern/metrics/lantern-largest-contentful-paint-test.js index 32dad6cf6172..0a066de059d0 100644 --- a/core/test/lib/lantern/metrics/lantern-largest-contentful-paint-test.js +++ b/core/test/lib/lantern/metrics/lantern-largest-contentful-paint-test.js @@ -6,11 +6,12 @@ import assert from 'assert/strict'; -import {LargestContentfulPaint} from '../../../../lib/lantern/metrics/LargestContentfulPaint.js'; -import {FirstContentfulPaint} from '../../../../lib/lantern/metrics/FirstContentfulPaint.js'; +import * as Lantern from '../../../../lib/lantern/lantern.js'; import {getComputationDataFromFixture} from './MetricTestUtils.js'; import {readJson} from '../../../test-utils.js'; +const {FirstContentfulPaint, LargestContentfulPaint} = Lantern.Metrics; + const trace = readJson('../../../fixtures/artifacts/paul/trace.json', import.meta); describe('Metrics: Lantern LCP', () => { diff --git a/core/test/lib/lantern/metrics/speed-index-test.js b/core/test/lib/lantern/metrics/speed-index-test.js index c2c5465ac6f6..a7a53c336a68 100644 --- a/core/test/lib/lantern/metrics/speed-index-test.js +++ b/core/test/lib/lantern/metrics/speed-index-test.js @@ -4,15 +4,15 @@ * SPDX-License-Identifier: Apache-2.0 */ +import * as Lantern from '../../../../lib/lantern/lantern.js'; import {readJson} from '../../../test-utils.js'; -import {SpeedIndex} from '../../../../lib/lantern/metrics/SpeedIndex.js'; -import {FirstContentfulPaint} from '../../../../lib/lantern/metrics/FirstContentfulPaint.js'; import {getComputationDataFromFixture} from './MetricTestUtils.js'; -import {constants} from '../../../../lib/lantern/lantern.js'; + +const {SpeedIndex, FirstContentfulPaint} = Lantern.Metrics; const trace = readJson('../../../fixtures/artifacts/progressive-app/trace.json', import.meta); -const defaultThrottling = constants.throttling.mobileSlow4G; +const defaultThrottling = Lantern.Simulation.Constants.throttling.mobileSlow4G; describe('Metrics: Lantern Speed Index', () => { it('should compute predicted value', async () => { diff --git a/core/test/lib/lantern/page-dependency-graph-test.js b/core/test/lib/lantern/page-dependency-graph-test.js index 9b2591e0faac..03214e9661ed 100644 --- a/core/test/lib/lantern/page-dependency-graph-test.js +++ b/core/test/lib/lantern/page-dependency-graph-test.js @@ -6,8 +6,9 @@ import assert from 'assert/strict'; -import {PageDependencyGraph} from '../../../lib/lantern/PageDependencyGraph.js'; -import {NetworkRequestTypes} from '../../../lib/lantern/lantern.js'; +import * as Lantern from '../../../lib/lantern/lantern.js'; + +const {PageDependencyGraph, NetworkRequestTypes} = Lantern; function createRequest( requestId, diff --git a/core/test/lib/lantern/simulator/connection-pool-test.js b/core/test/lib/lantern/simulation/connection-pool-test.js similarity index 98% rename from core/test/lib/lantern/simulator/connection-pool-test.js rename to core/test/lib/lantern/simulation/connection-pool-test.js index 04ba5d4f1b99..e3a724371268 100644 --- a/core/test/lib/lantern/simulator/connection-pool-test.js +++ b/core/test/lib/lantern/simulation/connection-pool-test.js @@ -7,9 +7,11 @@ import assert from 'assert/strict'; import {URL} from 'url'; -import {ConnectionPool} from '../../../../lib/lantern/simulator/ConnectionPool.js'; +import * as Lantern from '../../../../lib/lantern/lantern.js'; -describe('DependencyGraph/Simulator/ConnectionPool', () => { +const {ConnectionPool} = Lantern.Simulation; + +describe('ConnectionPool', () => { const rtt = 100; const throughput = 10000 * 1024; let requestId; diff --git a/core/test/lib/lantern/simulator/dns-cache-test.js b/core/test/lib/lantern/simulation/dns-cache-test.js similarity index 95% rename from core/test/lib/lantern/simulator/dns-cache-test.js rename to core/test/lib/lantern/simulation/dns-cache-test.js index bb0f87cf84cf..bbe372f0c852 100644 --- a/core/test/lib/lantern/simulator/dns-cache-test.js +++ b/core/test/lib/lantern/simulation/dns-cache-test.js @@ -4,11 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ -import {DNSCache} from '../../../../lib/lantern/simulator/DNSCache.js'; +import * as Lantern from '../../../../lib/lantern/lantern.js'; + +const {DNSCache} = Lantern.Simulation; const MULTIPLIER = DNSCache.RTT_MULTIPLIER; -describe('DependencyGraph/Simulator/DNSCache', () => { +describe('DNSCache', () => { let dns; let request; diff --git a/core/test/lib/lantern/simulator/network-analyzer-test.js b/core/test/lib/lantern/simulation/network-analyzer-test.js similarity index 97% rename from core/test/lib/lantern/simulator/network-analyzer-test.js rename to core/test/lib/lantern/simulation/network-analyzer-test.js index 48a120a1f005..53e296ed9f67 100644 --- a/core/test/lib/lantern/simulator/network-analyzer-test.js +++ b/core/test/lib/lantern/simulation/network-analyzer-test.js @@ -6,12 +6,12 @@ import assert from 'assert/strict'; -import * as Lantern from '../../../../lib/lantern/types/lantern.js'; -import {NetworkAnalyzer} from '../../../../lib/lantern/simulator/NetworkAnalyzer.js'; -import * as TraceEngineComputationData from '../../../../lib/lantern/TraceEngineComputationData.js'; +import * as Lantern from '../../../../lib/lantern/lantern.js'; import {readJson} from '../../../test-utils.js'; import {runTraceEngine} from '../metrics/MetricTestUtils.js'; +const {NetworkAnalyzer} = Lantern.Simulation; + const trace = readJson('../../../fixtures/artifacts/paul/trace.json', import.meta); const traceWithRedirect = readJson('../../../fixtures/artifacts/redirect/trace.json', import.meta); @@ -22,10 +22,10 @@ async function createRequests(trace) { const traceEngineData = await runTraceEngine( /** @type {TraceEngine.Types.TraceEvents.TraceEventData[]} */ (trace.traceEvents) ); - return TraceEngineComputationData.createNetworkRequests(trace, traceEngineData); + return Lantern.TraceEngineComputationData.createNetworkRequests(trace, traceEngineData); } -describe('DependencyGraph/Simulator/NetworkAnalyzer', () => { +describe('NetworkAnalyzer', () => { afterEach(() => { global.isLightrider = undefined; }); diff --git a/core/test/lib/lantern/simulator/simulator-test.js b/core/test/lib/lantern/simulation/simulator-test.js similarity index 96% rename from core/test/lib/lantern/simulator/simulator-test.js rename to core/test/lib/lantern/simulation/simulator-test.js index 97d75cf80991..9f08ea28cea9 100644 --- a/core/test/lib/lantern/simulator/simulator-test.js +++ b/core/test/lib/lantern/simulation/simulator-test.js @@ -6,15 +6,13 @@ import assert from 'assert/strict'; -import * as Lantern from '../../../../lib/lantern/Metric.js'; -import {NetworkNode} from '../../../../lib/lantern/NetworkNode.js'; -import {CPUNode} from '../../../../lib/lantern/CpuNode.js'; -import {Simulator} from '../../../../lib/lantern/simulator/Simulator.js'; -import {DNSCache} from '../../../../lib/lantern/simulator/DNSCache.js'; +import * as Lantern from '../../../../lib/lantern/lantern.js'; import {readJson} from '../../../test-utils.js'; -import * as TraceEngineComputationData from '../../../../lib/lantern/TraceEngineComputationData.js'; import {runTraceEngine} from '../metrics/MetricTestUtils.js'; +const {NetworkNode, CPUNode} = Lantern; +const {Simulator, DNSCache} = Lantern.Simulation; + const pwaTrace = readJson('../../../fixtures/artifacts/progressive-app/trace.json', import.meta); let nextRequestId = 1; @@ -22,12 +20,12 @@ let nextTid = 1; /** * @param {Lantern.Trace} trace - * @param {Lantern.Simulation.URL=} URL */ async function createGraph(trace) { const traceEngineData = await runTraceEngine(trace.traceEvents); - const requests = TraceEngineComputationData.createNetworkRequests(trace, traceEngineData); - return TraceEngineComputationData.createGraph(requests, trace, traceEngineData); + const requests = + Lantern.TraceEngineComputationData.createNetworkRequests(trace, traceEngineData); + return Lantern.TraceEngineComputationData.createGraph(requests, trace, traceEngineData); } function request(opts) { diff --git a/core/test/lib/lantern/simulator/tcp-connection-test.js b/core/test/lib/lantern/simulation/tcp-connection-test.js similarity index 99% rename from core/test/lib/lantern/simulator/tcp-connection-test.js rename to core/test/lib/lantern/simulation/tcp-connection-test.js index fbabb4bec7ae..515b2cd2d76a 100644 --- a/core/test/lib/lantern/simulator/tcp-connection-test.js +++ b/core/test/lib/lantern/simulation/tcp-connection-test.js @@ -6,7 +6,9 @@ import assert from 'assert/strict'; -import {TcpConnection} from '../../../../lib/lantern/simulator/TcpConnection.js'; +import * as Lantern from '../../../../lib/lantern/lantern.js'; + +const {TcpConnection} = Lantern.Simulation; describe('DependencyGraph/Simulator/TcpConnection', () => { describe('#constructor', () => { diff --git a/core/test/lib/lantern/tbt-utils-test.js b/core/test/lib/lantern/tbt-utils-test.js index 05862e10488b..a1bceecff2d7 100644 --- a/core/test/lib/lantern/tbt-utils-test.js +++ b/core/test/lib/lantern/tbt-utils-test.js @@ -4,7 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ -import {calculateSumOfBlockingTime} from '../../../lib/lantern/TBTUtils.js'; +import * as Lantern from '../../../lib/lantern/lantern.js'; + +const {calculateSumOfBlockingTime} = Lantern.TBTUtils; describe('TotalBlockingTime utils', () => { it('reports 0 when no task is longer than 50ms', () => { diff --git a/tsconfig.json b/tsconfig.json index 974dd92c2cfc..bda352ffb478 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -69,10 +69,10 @@ "core/test/lib/lantern/base-node-test.js", "core/test/lib/lantern/metrics/*", "core/test/lib/lantern/page-dependency-graph-test.js", - "core/test/lib/lantern/simulator/connection-pool-test.js", - "core/test/lib/lantern/simulator/dns-cache-test.js", - "core/test/lib/lantern/simulator/network-analyzer-test.js", - "core/test/lib/lantern/simulator/simulator-test.js", + "core/test/lib/lantern/simulation/connection-pool-test.js", + "core/test/lib/lantern/simulation/dns-cache-test.js", + "core/test/lib/lantern/simulation/network-analyzer-test.js", + "core/test/lib/lantern/simulation/simulator-test.js", "core/test/lib/lh-element-test.js", "core/test/lib/lighthouse-compatibility-test.js", "core/test/lib/manifest-parser-test.js", diff --git a/types/artifacts.d.ts b/types/artifacts.d.ts index 5ad1c731a638..2cbb827ef134 100644 --- a/types/artifacts.d.ts +++ b/types/artifacts.d.ts @@ -6,11 +6,10 @@ 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 * as Lantern from '../core/lib/lantern/lantern.js'; import {LayoutShiftRootCausesData} from '@paulirish/trace_engine/models/trace/root-causes/LayoutShift.js'; import {parseManifest} from '../core/lib/manifest-parser.js'; -import {Simulator} from '../core/lib/lantern/simulator/Simulator.js'; import {LighthouseError} from '../core/lib/lh-error.js'; import {NetworkRequest as _NetworkRequest} from '../core/lib/network-request.js'; import speedline from 'speedline-core'; @@ -566,7 +565,7 @@ declare module Artifacts { trace: Trace; settings: Audit.Context['settings']; gatherContext: Artifacts['GatherContext']; - simulator?: InstanceType; + simulator?: InstanceType; URL: Artifacts['URL']; } @@ -592,7 +591,7 @@ declare module Artifacts { throughput: number; } - type LanternMetric = Lantern.Metric; + type LanternMetric = Lantern.Metrics.Result; type Speedline = speedline.Output<'speedIndex'>; diff --git a/types/gatherer.d.ts b/types/gatherer.d.ts index 2d30439cc07c..5d818a1062ce 100644 --- a/types/gatherer.d.ts +++ b/types/gatherer.d.ts @@ -17,7 +17,7 @@ import Config from './config.js'; import Result from './lhr/lhr.js'; import Protocol from './protocol.js'; import Puppeteer from './puppeteer.js'; -import * as Lantern from '../core/lib/lantern/types/lantern.js'; +import * as Lantern from '../core/lib/lantern/lantern.js'; type CrdpEvents = CrdpMappings.Events; type CrdpCommands = CrdpMappings.Commands;