Rocky_Mountain_Vending/.pnpm-store/v10/files/d1/69ca7f9c4f972c40907f8a1baa16f94ee923dd695e016d5331e3ae4ff8e1d613722ba91c69eb25c2bc4ae9412a513e99a2bcb5d2b82a0abe4ce1363d94ea62
DMleadgen 46d973904b
Initial commit: Rocky Mountain Vending website
Next.js website for Rocky Mountain Vending company featuring:
- Product catalog with Stripe integration
- Service areas and parts pages
- Admin dashboard with Clerk authentication
- SEO optimized pages with JSON-LD structured data

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 16:22:15 -07:00

74 lines
3 KiB
Text

/**
* @license
* Copyright 2023 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import {makeComputedArtifact} from './computed-artifact.js';
import {NetworkRecords} from './network-records.js';
import {ProcessedNavigation} from './processed-navigation.js';
import {LighthouseError} from '../lib/lh-error.js';
/**
* @fileoverview Match the LCP event with the paint event to get the request of the image actually painted.
* This could differ from the `ImageElement` associated with the nodeId if e.g. the LCP
* was a pseudo-element associated with a node containing a smaller background-image.
*/
class LCPImageRecord {
/**
* @param {{trace: LH.Trace, devtoolsLog: LH.DevtoolsLog}} data
* @param {LH.Artifacts.ComputedContext} context
* @return {Promise<LH.Artifacts.NetworkRequest|undefined>}
*/
static async compute_(data, context) {
const {trace, devtoolsLog} = data;
const networkRecords = await NetworkRecords.request(devtoolsLog, context);
const processedNavigation = await ProcessedNavigation.request(trace, context);
if (processedNavigation.timings.largestContentfulPaint === undefined) {
throw new LighthouseError(LighthouseError.errors.NO_LCP);
}
// Use main-frame-only LCP to match the metric value.
const lcpEvent = processedNavigation.largestContentfulPaintEvt;
if (!lcpEvent) return;
const lcpImagePaintEvent = trace.traceEvents.filter(e => {
return e.name === 'LargestImagePaint::Candidate' &&
e.args.frame === lcpEvent.args.frame &&
e.args.data?.DOMNodeId === lcpEvent.args.data?.nodeId &&
e.args.data?.size === lcpEvent.args.data?.size;
// Get last candidate, in case there was more than one.
}).sort((a, b) => b.ts - a.ts)[0];
const lcpUrl = lcpImagePaintEvent?.args.data?.imageUrl;
if (!lcpUrl) return;
const candidates = networkRecords.filter(record => {
return record.url === lcpUrl &&
record.finished &&
// Same frame as LCP trace event.
record.frameId === lcpImagePaintEvent.args.frame &&
record.networkRequestTime < (processedNavigation.timestamps.largestContentfulPaint || 0);
}).map(record => {
// Follow any redirects to find the real image request.
while (record.redirectDestination) {
record = record.redirectDestination;
}
return record;
}).filter(record => {
// Don't select if also loaded by some other means (xhr, etc). `resourceType`
// isn't set on redirect _sources_, so have to check after following redirects.
return record.resourceType === 'Image';
});
// If there are still multiple candidates, at this point it appears the page
// simply made multiple requests for the image. The first loaded is the best
// guess of the request that made the image available for use.
return candidates.sort((a, b) => a.networkEndTime - b.networkEndTime)[0];
}
}
const LCPImageRecordComputed = makeComputedArtifact(LCPImageRecord, ['devtoolsLog', 'trace']);
export {LCPImageRecordComputed as LCPImageRecord};