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>
185 lines
No EOL
6.9 KiB
Text
185 lines
No EOL
6.9 KiB
Text
// Copyright 2022 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
import * as Helpers from '../helpers/helpers.js';
|
|
import * as Types from '../types/types.js';
|
|
/**
|
|
* IMPORTANT!
|
|
* See UserTimings.md in this directory for some handy documentation on
|
|
* UserTimings and the trace events we parse currently.
|
|
**/
|
|
let syntheticEvents = [];
|
|
// There are two events dispatched for performance.measure calls: one to
|
|
// represent the measured timing in the tracing clock (which we type as
|
|
// PerformanceMeasure) and another one for the call itself (which we
|
|
// type as UserTimingMeasure). The two events corresponding to the same
|
|
// call are linked together by a common trace_id. The reason two events
|
|
// are dispatched is because the first was originally added with the
|
|
// implementation of the performance.measure API and it uses an
|
|
// overridden timestamp and duration. To prevent breaking potential deps
|
|
// created since then, a second event was added instead of changing the
|
|
// params of the first.
|
|
const measureTraceByTraceId = new Map();
|
|
const performanceMeasureEvents = [];
|
|
const performanceMarkEvents = [];
|
|
const consoleTimings = [];
|
|
let timestampEvents = [];
|
|
export function reset() {
|
|
syntheticEvents.length = 0;
|
|
performanceMeasureEvents.length = 0;
|
|
performanceMarkEvents.length = 0;
|
|
consoleTimings.length = 0;
|
|
timestampEvents.length = 0;
|
|
measureTraceByTraceId.clear();
|
|
}
|
|
const resourceTimingNames = [
|
|
'workerStart',
|
|
'redirectStart',
|
|
'redirectEnd',
|
|
'fetchStart',
|
|
'domainLookupStart',
|
|
'domainLookupEnd',
|
|
'connectStart',
|
|
'connectEnd',
|
|
'secureConnectionStart',
|
|
'requestStart',
|
|
'responseStart',
|
|
'responseEnd',
|
|
];
|
|
const navTimingNames = [
|
|
'navigationStart',
|
|
'unloadEventStart',
|
|
'unloadEventEnd',
|
|
'redirectStart',
|
|
'redirectEnd',
|
|
'fetchStart',
|
|
'commitNavigationEnd',
|
|
'domainLookupStart',
|
|
'domainLookupEnd',
|
|
'connectStart',
|
|
'connectEnd',
|
|
'secureConnectionStart',
|
|
'requestStart',
|
|
'responseStart',
|
|
'responseEnd',
|
|
'domLoading',
|
|
'domInteractive',
|
|
'domContentLoadedEventStart',
|
|
'domContentLoadedEventEnd',
|
|
'domComplete',
|
|
'loadEventStart',
|
|
'loadEventEnd',
|
|
];
|
|
// These are events dispatched under the blink.user_timing category
|
|
// but that the user didn't add. Filter them out so that they do not
|
|
// Appear in the timings track (they still appear in the main thread
|
|
// flame chart).
|
|
const ignoredNames = [...resourceTimingNames, ...navTimingNames];
|
|
function getEventTimings(event) {
|
|
if ('dur' in event) {
|
|
// It's a SyntheticEventPair.
|
|
return { start: event.ts, end: Types.Timing.Micro(event.ts + (event.dur ?? 0)) };
|
|
}
|
|
if (Types.Events.isConsoleTimeStamp(event)) {
|
|
const { start, end } = event.args.data || {};
|
|
if (typeof start === 'number' && typeof end === 'number') {
|
|
return { start: Types.Timing.Micro(start), end: Types.Timing.Micro(end) };
|
|
}
|
|
}
|
|
// A ConsoleTimeStamp without start/end is just a point in time, so dur is 0.
|
|
return { start: event.ts, end: event.ts };
|
|
}
|
|
function getEventTrack(event) {
|
|
if (event.cat === 'blink.user_timing') {
|
|
// This is a SyntheticUserTimingPair
|
|
const detailString = event.args.data.beginEvent.args?.detail;
|
|
if (detailString) {
|
|
const details = Helpers.Trace.parseDevtoolsDetails(detailString, 'devtools');
|
|
if (details && 'track' in details) {
|
|
return details.track;
|
|
}
|
|
}
|
|
}
|
|
else if (Types.Events.isConsoleTimeStamp(event)) {
|
|
const track = event.args.data?.track;
|
|
return typeof track === 'string' ? track : undefined;
|
|
}
|
|
// SyntheticConsoleTimingPair does not have track info.
|
|
return undefined;
|
|
}
|
|
/**
|
|
* Similar to the default {@see Helpers.Trace.eventTimeComparator}
|
|
* but with a twist:
|
|
* In case of equal start and end times, put the second event (within a
|
|
* track) first.
|
|
*
|
|
* Explanation:
|
|
* User timing entries come as trace events dispatched when
|
|
* performance.measure/mark is called. The trace events buffered in
|
|
* devtools frontend are sorted by the start time. If their start time
|
|
* is the same, then the event for the first call will appear first.
|
|
*
|
|
* When entries are meant to be stacked, the corresponding
|
|
* performance.measure calls usually are done in bottom-up direction:
|
|
* calls for children first and for parent later (because the call
|
|
* is usually done when the measured task is over). This means that
|
|
* when two user timing events have the same start and end time, usually
|
|
* the second event is the parent of the first. Hence the switch.
|
|
*
|
|
*/
|
|
export function userTimingComparator(a, b, originalArray) {
|
|
const { start: aStart, end: aEnd } = getEventTimings(a);
|
|
const { start: bStart, end: bEnd } = getEventTimings(b);
|
|
const timeDifference = Helpers.Trace.compareBeginAndEnd(aStart, bStart, aEnd, bEnd);
|
|
if (timeDifference) {
|
|
return timeDifference;
|
|
}
|
|
// Never re-order entries across different tracks.
|
|
const aTrack = getEventTrack(a);
|
|
const bTrack = getEventTrack(b);
|
|
if (aTrack !== bTrack) {
|
|
return 0; // Preserve current positions.
|
|
}
|
|
// Prefer the event located in a further position in the original array.
|
|
const aIndex = originalArray.indexOf(a);
|
|
const bIndex = originalArray.indexOf(b);
|
|
return bIndex - aIndex;
|
|
}
|
|
export function handleEvent(event) {
|
|
if (ignoredNames.includes(event.name)) {
|
|
return;
|
|
}
|
|
if (Types.Events.isUserTimingMeasure(event)) {
|
|
measureTraceByTraceId.set(event.args.traceId, event);
|
|
}
|
|
if (Types.Events.isPerformanceMeasure(event)) {
|
|
performanceMeasureEvents.push(event);
|
|
return;
|
|
}
|
|
if (Types.Events.isPerformanceMark(event)) {
|
|
performanceMarkEvents.push(event);
|
|
}
|
|
if (Types.Events.isConsoleTime(event)) {
|
|
consoleTimings.push(event);
|
|
}
|
|
if (Types.Events.isConsoleTimeStamp(event)) {
|
|
timestampEvents.push(event);
|
|
}
|
|
}
|
|
export async function finalize() {
|
|
const asyncEvents = [...performanceMeasureEvents, ...consoleTimings];
|
|
syntheticEvents = Helpers.Trace.createMatchedSortedSyntheticEvents(asyncEvents);
|
|
syntheticEvents = syntheticEvents.sort((a, b) => userTimingComparator(a, b, [...syntheticEvents]));
|
|
timestampEvents = timestampEvents.sort((a, b) => userTimingComparator(a, b, [...timestampEvents]));
|
|
}
|
|
export function data() {
|
|
return {
|
|
performanceMeasures: syntheticEvents.filter(e => e.cat === 'blink.user_timing'),
|
|
consoleTimings: syntheticEvents.filter(e => e.cat === 'blink.console'),
|
|
// TODO(crbug/41484172): UserTimingsHandler.test.ts fails if this is not copied.
|
|
performanceMarks: [...performanceMarkEvents],
|
|
timestampEvents: [...timestampEvents],
|
|
measureTraceByTraceId: new Map(measureTraceByTraceId),
|
|
};
|
|
}
|
|
//# sourceMappingURL=UserTimingsHandler.js.map |