diff --git a/BUCK b/BUCK index f6992f16192..b29a350994e 100644 --- a/BUCK +++ b/BUCK @@ -10,6 +10,9 @@ load( ) load( "//tools/build_defs/oss:rn_defs.bzl", + "ANDROID", + "APPLE", + "CXX", "HERMES_BYTECODE_VERSION", "IOS", "RCT_IMAGE_DATA_DECODER_SOCKET", @@ -1453,3 +1456,28 @@ rn_xplat_cxx_library2( "//fbobjc/VendorLib/react-native-maps:react-native-maps", ], ) + +rn_xplat_cxx_library2( + name = "RCTWebPerformance", + srcs = glob([ + "Libraries/WebPerformance/**/*.cpp", + ]), + header_namespace = "", + exported_headers = subdir_glob( + [("Libraries/WebPerformance", "*.h")], + prefix = "RCTWebPerformance", + ), + fbandroid_compiler_flags = [ + "-fexceptions", + "-frtti", + ], + labels = [ + "depslint_never_remove", + "pfh:ReactNative_CommonInfrastructurePlaceholder", + ], + platforms = (ANDROID, APPLE, CXX), + visibility = ["PUBLIC"], + deps = [ + ":FBReactNativeSpecJSI", + ], +) diff --git a/Libraries/WebPerformance/NativePerformanceObserver.cpp b/Libraries/WebPerformance/NativePerformanceObserver.cpp new file mode 100644 index 00000000000..32ab293e6cb --- /dev/null +++ b/Libraries/WebPerformance/NativePerformanceObserver.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "NativePerformanceObserver.h" +#include + +namespace facebook::react { + +NativePerformanceObserver::NativePerformanceObserver( + std::shared_ptr jsInvoker) + : NativePerformanceObserverCxxSpec(std::move(jsInvoker)) {} + +void NativePerformanceObserver::startReporting( + jsi::Runtime &rt, + std::string entryType) { + LOG(INFO) << "Started reporting perf entry type: " << entryType; +} + +void NativePerformanceObserver::stopReporting( + jsi::Runtime &rt, + std::string entryType) { + LOG(INFO) << "Stopped reporting perf entry type: " << entryType; +} + +std::vector NativePerformanceObserver::getPendingEntries( + jsi::Runtime &rt) { + return std::vector{}; +} + +void NativePerformanceObserver::setOnPerformanceEntryCallback( + jsi::Runtime &rt, + std::optional> callback) { + callback_ = callback; + LOG(INFO) << "setOnPerformanceEntryCallback: " + << (callback ? "non-empty" : "empty"); +} + +} // namespace facebook::react diff --git a/Libraries/WebPerformance/NativePerformanceObserver.h b/Libraries/WebPerformance/NativePerformanceObserver.h new file mode 100644 index 00000000000..9bd015d572e --- /dev/null +++ b/Libraries/WebPerformance/NativePerformanceObserver.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "NativePerformanceObserver_RawPerformanceEntry.h" + +namespace facebook::react { + +class NativePerformanceObserver + : public NativePerformanceObserverCxxSpec, + std::enable_shared_from_this { + public: + NativePerformanceObserver(std::shared_ptr jsInvoker); + + void startReporting(jsi::Runtime &rt, std::string entryType); + + void stopReporting(jsi::Runtime &rt, std::string entryType); + + std::vector getPendingEntries(jsi::Runtime &rt); + + void setOnPerformanceEntryCallback( + jsi::Runtime &rt, + std::optional> callback); + + private: + std::optional> callback_; +}; + +} // namespace facebook::react diff --git a/Libraries/NativeModules/specs/NativePerformanceObserverCxx.js b/Libraries/WebPerformance/NativePerformanceObserver.js similarity index 58% rename from Libraries/NativeModules/specs/NativePerformanceObserverCxx.js rename to Libraries/WebPerformance/NativePerformanceObserver.js index 420b495e091..78b86b099ae 100644 --- a/Libraries/NativeModules/specs/NativePerformanceObserverCxx.js +++ b/Libraries/WebPerformance/NativePerformanceObserver.js @@ -8,11 +8,9 @@ * @format */ -import type {TurboModule} from '../../TurboModule/RCTExport'; +import type {TurboModule} from '../TurboModule/RCTExport'; -import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; - -export type RawTimeStamp = number; +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export const RawPerformanceEntryTypeValues = { UNDEFINED: 0, @@ -23,22 +21,21 @@ export type RawPerformanceEntryType = number; export type RawPerformanceEntry = $ReadOnly<{ name: string, entryType: RawPerformanceEntryType, - startTime: RawTimeStamp, + startTime: number, duration: number, - // For "event" entries only: - processingStart?: RawTimeStamp, - processingEnd?: RawTimeStamp, - interactionId?: RawTimeStamp, + processingStart?: number, + processingEnd?: number, + interactionId?: number, }>; -export type RawPerformanceEntryList = $ReadOnlyArray; - export interface Spec extends TurboModule { +startReporting: (entryType: string) => void; +stopReporting: (entryType: string) => void; - +getPendingEntries: () => RawPerformanceEntryList; + +getPendingEntries: () => $ReadOnlyArray; +setOnPerformanceEntryCallback: (callback?: () => void) => void; } -export default (TurboModuleRegistry.get('PerformanceObserver'): ?Spec); +export default (TurboModuleRegistry.get( + 'NativePerformanceObserverCxx', +): ?Spec); diff --git a/Libraries/WebPerformance/NativePerformanceObserver_RawPerformanceEntry.h b/Libraries/WebPerformance/NativePerformanceObserver_RawPerformanceEntry.h new file mode 100644 index 00000000000..1469bf196e3 --- /dev/null +++ b/Libraries/WebPerformance/NativePerformanceObserver_RawPerformanceEntry.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include + +namespace facebook::react { + +struct RawPerformanceEntry { + std::string name; + int32_t entryType; + double startTime; + double duration; + // For "event" entries only: + std::optional processingStart; + std::optional processingEnd; + std::optional interactionId; +}; + +template <> +struct Bridging { + static RawPerformanceEntry fromJs( + jsi::Runtime &rt, + const jsi::Object &value, + const std::shared_ptr &jsInvoker) { + RawPerformanceEntry result{ + bridging::fromJs( + rt, value.getProperty(rt, "name"), jsInvoker), + bridging::fromJs( + rt, value.getProperty(rt, "entryType"), jsInvoker), + bridging::fromJs( + rt, value.getProperty(rt, "startTime"), jsInvoker), + bridging::fromJs( + rt, value.getProperty(rt, "duration"), jsInvoker), + bridging::fromJs>( + rt, value.getProperty(rt, "processingStart"), jsInvoker), + bridging::fromJs>( + rt, value.getProperty(rt, "processingEnd"), jsInvoker), + bridging::fromJs>( + rt, value.getProperty(rt, "interactionId"), jsInvoker), + }; + return result; + } + + static jsi::Object toJs(jsi::Runtime &rt, const RawPerformanceEntry &value) { + auto result = facebook::jsi::Object(rt); + result.setProperty(rt, "name", bridging::toJs(rt, value.name)); + result.setProperty(rt, "entryType", bridging::toJs(rt, value.entryType)); + result.setProperty(rt, "startTime", bridging::toJs(rt, value.startTime)); + result.setProperty(rt, "duration", bridging::toJs(rt, value.duration)); + if (value.processingStart) { + result.setProperty( + rt, + "processingStart", + bridging::toJs(rt, value.processingStart.value())); + } + if (value.processingEnd) { + result.setProperty( + rt, "processingEnd", bridging::toJs(rt, value.processingEnd.value())); + } + if (value.interactionId) { + result.setProperty( + rt, "interactionId", bridging::toJs(rt, value.interactionId.value())); + } + return result; + } +}; + +} // namespace facebook::react diff --git a/Libraries/WebPerformance/PerformanceObserver.js b/Libraries/WebPerformance/PerformanceObserver.js index aa750b2166e..dc9a0c4aff6 100644 --- a/Libraries/WebPerformance/PerformanceObserver.js +++ b/Libraries/WebPerformance/PerformanceObserver.js @@ -10,12 +10,11 @@ import type { RawPerformanceEntry, - RawPerformanceEntryList, RawPerformanceEntryType, -} from '../NativeModules/specs/NativePerformanceObserverCxx'; +} from './NativePerformanceObserver'; -import NativePerformanceObserver from '../NativeModules/specs/NativePerformanceObserverCxx'; import warnOnce from '../Utilities/warnOnce'; +import NativePerformanceObserver from './NativePerformanceObserver'; export type HighResTimeStamp = number; // TODO: Extend once new types (such as event) are supported. @@ -195,7 +194,7 @@ export default class PerformanceObserver { }); _observers.delete(this); if (_observers.size === 0) { - NativePerformanceObserver.setOnPerformanceEntryCallback(); + NativePerformanceObserver.setOnPerformanceEntryCallback(undefined); _onPerformanceEntryCallbackIsSet = false; } } @@ -210,8 +209,7 @@ function onPerformanceEntry() { if (!NativePerformanceObserver) { return; } - const rawEntries: RawPerformanceEntryList = - NativePerformanceObserver.getPendingEntries(); + const rawEntries = NativePerformanceObserver.getPendingEntries(); const entries = rawEntries.map(rawToPerformanceEntry); _observers.forEach(observer => { const entriesForObserver: PerformanceEntryList = entries.filter(entry =>