Add internal support for PerformanceResourceTiming (#50996)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/50996

Adds a representation of the [`PerformanceResourceTiming`](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming) event type to the Web Performance subsystem, ahead of integration with our network event reporting.

Changelog: [Internal]

Reviewed By: rubennorte

Differential Revision: D73861431

fbshipit-source-id: 8258058c432727808d30c338bba79ca92a17c1c8
This commit is contained in:
Alex Hunt
2025-05-01 22:40:39 -07:00
committed by Facebook GitHub Bot
parent 1135f10e05
commit baf895c239
9 changed files with 68 additions and 4 deletions
@@ -9696,7 +9696,12 @@ declare export default class Performance {
exports[`public API should not change unintentionally src/private/webapis/performance/PerformanceEntry.js 1`] = `
"export type DOMHighResTimeStamp = number;
export type PerformanceEntryType = \\"mark\\" | \\"measure\\" | \\"event\\" | \\"longtask\\";
export type PerformanceEntryType =
| \\"mark\\"
| \\"measure\\"
| \\"event\\"
| \\"longtask\\"
| \\"resource\\";
export type PerformanceEntryJSON = {
name: string,
entryType: PerformanceEntryType,
@@ -65,6 +65,16 @@ NativePerformanceEntry toNativePerformanceEntry(const PerformanceEntry& entry) {
nativeEntry.processingEnd = eventEntry.processingEnd;
nativeEntry.interactionId = eventEntry.interactionId;
}
if (std::holds_alternative<PerformanceResourceTiming>(entry)) {
auto resourceEntry = std::get<PerformanceResourceTiming>(entry);
nativeEntry.fetchStart = resourceEntry.fetchStart;
nativeEntry.requestStart = resourceEntry.requestStart;
nativeEntry.connectStart = resourceEntry.connectStart;
nativeEntry.connectEnd = resourceEntry.connectEnd;
nativeEntry.responseStart = resourceEntry.responseStart;
nativeEntry.responseEnd = resourceEntry.responseEnd;
nativeEntry.responseStatus = resourceEntry.responseStatus;
}
return nativeEntry;
}
@@ -61,6 +61,15 @@ struct NativePerformanceEntry {
std::optional<DOMHighResTimeStamp> processingStart;
std::optional<DOMHighResTimeStamp> processingEnd;
std::optional<PerformanceEntryInteractionId> interactionId;
// For PerformanceResourceTiming only
std::optional<DOMHighResTimeStamp> fetchStart;
std::optional<DOMHighResTimeStamp> requestStart;
std::optional<DOMHighResTimeStamp> connectStart;
std::optional<DOMHighResTimeStamp> connectEnd;
std::optional<DOMHighResTimeStamp> responseStart;
std::optional<DOMHighResTimeStamp> responseEnd;
std::optional<int> responseStatus;
};
template <>
@@ -8,6 +8,7 @@
#pragma once
#include <react/timing/primitives.h>
#include <optional>
#include <string>
#include <variant>
@@ -21,7 +22,8 @@ enum class PerformanceEntryType {
MEASURE = 2,
EVENT = 3,
LONGTASK = 4,
_NEXT = 5,
RESOURCE = 5,
_NEXT = 6,
};
struct AbstractPerformanceEntry {
@@ -51,11 +53,26 @@ struct PerformanceLongTaskTiming : AbstractPerformanceEntry {
PerformanceEntryType::LONGTASK;
};
struct PerformanceResourceTiming : AbstractPerformanceEntry {
static constexpr PerformanceEntryType entryType =
PerformanceEntryType::RESOURCE;
/** Aligns with `startTime`. */
std::optional<DOMHighResTimeStamp> fetchStart;
std::optional<DOMHighResTimeStamp> requestStart;
std::optional<DOMHighResTimeStamp> connectStart;
std::optional<DOMHighResTimeStamp> connectEnd;
std::optional<DOMHighResTimeStamp> responseStart;
/** Aligns with `duration`. */
std::optional<DOMHighResTimeStamp> responseEnd;
std::optional<int> responseStatus;
};
using PerformanceEntry = std::variant<
PerformanceMark,
PerformanceMeasure,
PerformanceEventTiming,
PerformanceLongTaskTiming>;
PerformanceLongTaskTiming,
PerformanceResourceTiming>;
struct PerformanceEntrySorter {
bool operator()(const PerformanceEntry& lhs, const PerformanceEntry& rhs) {
@@ -109,6 +109,7 @@ class PerformanceEntryReporter {
PerformanceEntryCircularBuffer longTaskBuffer_{LONG_TASK_BUFFER_SIZE};
PerformanceEntryKeyedBuffer markBuffer_;
PerformanceEntryKeyedBuffer measureBuffer_;
PerformanceEntryKeyedBuffer resourceBuffer_;
std::unordered_map<std::string, uint32_t> eventCounts_;
@@ -127,6 +128,8 @@ class PerformanceEntryReporter {
return measureBuffer_;
case PerformanceEntryType::LONGTASK:
return longTaskBuffer_;
case PerformanceEntryType::RESOURCE:
return resourceBuffer_;
case PerformanceEntryType::_NEXT:
throw std::logic_error("Cannot get buffer for _NEXT entry type");
}
@@ -143,6 +146,8 @@ class PerformanceEntryReporter {
return measureBuffer_;
case PerformanceEntryType::LONGTASK:
return longTaskBuffer_;
case PerformanceEntryType::RESOURCE:
return resourceBuffer_;
case PerformanceEntryType::_NEXT:
throw std::logic_error("Cannot get buffer for _NEXT entry type");
}
@@ -51,6 +51,7 @@ namespace facebook::react {
"PerformanceEntryType::MARK",
"PerformanceEntryType::MEASURE",
"PerformanceEntryType::EVENT",
"PerformanceEntryType::RESOURCE",
};
return std::visit(
@@ -11,7 +11,12 @@
// flowlint unsafe-getters-setters:off
export type DOMHighResTimeStamp = number;
export type PerformanceEntryType = 'mark' | 'measure' | 'event' | 'longtask';
export type PerformanceEntryType =
| 'mark'
| 'measure'
| 'event'
| 'longtask'
| 'resource';
export type PerformanceEntryJSON = {
name: string,
@@ -24,6 +24,7 @@ export const RawPerformanceEntryTypeValues = {
MEASURE: 2,
EVENT: 3,
LONGTASK: 4,
RESOURCE: 5,
};
export function rawToPerformanceEntry(
@@ -95,6 +96,8 @@ export function performanceEntryTypeToRaw(
return RawPerformanceEntryTypeValues.EVENT;
case 'longtask':
return RawPerformanceEntryTypeValues.LONGTASK;
case 'resource':
return RawPerformanceEntryTypeValues.RESOURCE;
default:
// Verify exhaustive check with Flow
(type: empty);
@@ -28,6 +28,15 @@ export type RawPerformanceEntry = {
processingStart?: number,
processingEnd?: number,
interactionId?: number,
// For PerformanceResourceTiming only
fetchStart?: number,
requestStart?: number,
connectStart?: number,
connectEnd?: number,
responseStart?: number,
responseEnd?: number,
responseStatus?: number,
};
export type OpaqueNativeObserverHandle = mixed;