From 92817c4bac4873ee17a5e1b907afed48518f098c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Mon, 18 Nov 2024 13:27:26 +0100 Subject: [PATCH 1/6] wip: re-enable performance metrics --- .gitignore | 2 ++ lib/Onyx.ts | 19 +++++++++++++++++++ lib/metrics.ts | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/types.ts | 6 ++++++ package.json | 3 +-- 5 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 lib/metrics.ts diff --git a/.gitignore b/.gitignore index a46d06d84..5592c6d47 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,5 @@ yalc.lock # Perf tests .reassure + +example/ \ No newline at end of file diff --git a/lib/Onyx.ts b/lib/Onyx.ts index 91c44e91b..14de5fb70 100644 --- a/lib/Onyx.ts +++ b/lib/Onyx.ts @@ -40,6 +40,7 @@ function init({ maxCachedKeysCount = 1000, shouldSyncMultipleInstances = Boolean(global.localStorage), debugSetState = false, + enablePerformanceMetrics = false, }: InitOptions): void { Storage.init(); @@ -65,6 +66,24 @@ function init({ Promise.all([OnyxUtils.addAllSafeEvictionKeysToRecentlyAccessedList(), OnyxUtils.initializeWithDefaultKeyStates()]).then(OnyxUtils.getDeferredInitTask().resolve); } +function applyDecorators() { + // We're requiring the script dynamically here so that it's only evaluated when decorators are used + // eslint-disable-next-line @typescript-eslint/no-var-requires + const decorate = require('./metrics'); + + // Re-assign with decorated functions + /* eslint-disable no-func-assign */ + connect = decorate(connect, 'Onyx:connect'); + set = decorate(set, 'Onyx:set'); + multiSet = decorate(multiSet, 'Onyx:multiSet'); + clear = decorate(clear, 'Onyx:clear'); + merge = decorate(merge, 'Onyx:merge'); + mergeCollection = decorate(mergeCollection, 'Onyx:mergeCollection'); + update = decorate(update, 'Onyx:update'); + clear = decorate(clear, 'Onyx:clear'); + /* eslint-enable */ +} + /** * Connects to an Onyx key given the options passed and listens to its changes. * diff --git a/lib/metrics.ts b/lib/metrics.ts new file mode 100644 index 000000000..341f0cd16 --- /dev/null +++ b/lib/metrics.ts @@ -0,0 +1,49 @@ +import performance from 'react-native-performance'; +import type {PerformanceMark} from 'react-native-performance'; + +const decoratedAliases = new Set(); + +/** + * Capture a measurement between the start mark and now + */ +function measureMarkToNow(startMark: PerformanceMark, detail: Record) { + performance.measure(`${startMark.name} [${startMark.detail.args.toString()}]`, { + start: startMark.startTime, + end: performance.now(), + detail: {...startMark.detail, ...detail}, + }); +} + +/** + * Wraps a function with metrics capturing logic + */ +function decorateWithMetrics>(func: (...args: Args) => ReturnType, alias = func.name) { + if (decoratedAliases.has(alias)) { + throw new Error(`"${alias}" is already decorated`); + } + + decoratedAliases.add(alias); + function decorated(...args: Args) { + const mark = performance.mark(alias, {detail: {args, alias}}); + + const originalPromise = func(...args); + + /* + * The handlers added here are not affecting the original promise + * They create a separate chain that's not exposed (returned) to the original caller + */ + originalPromise + .then((result) => { + measureMarkToNow(mark, {result}); + }) + .catch((error) => { + measureMarkToNow(mark, {error}); + }); + + return originalPromise; + } + + return decorated; +} + +export default decorateWithMetrics; diff --git a/lib/types.ts b/lib/types.ts index 3a6696ce1..685a0fc39 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -462,6 +462,12 @@ type InitOptions = { /** Enables debugging setState() calls to connected components */ debugSetState?: boolean; + + /** + * If enabled it will use the performance API to measure the time taken by Onyx operations. + * @default false + */ + enablePerformanceMetrics?: boolean; }; // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/package.json b/package.json index 75a5503e3..58d1ae516 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,7 @@ "README.md", "LICENSE.md" ], - "main": "dist/index.js", - "types": "dist/index.d.ts", + "main": "lib/index.ts", "scripts": { "lint": "eslint .", "typecheck": "tsc --noEmit", From 3f2182778c5cfbacbf220902d7f92b2c3ce0aecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Wed, 20 Nov 2024 16:28:28 +0100 Subject: [PATCH 2/6] add decorator pattern also to onyx utils --- lib/GlobalSettings.ts | 34 +++++++++++++++++ lib/Onyx.ts | 46 +++++++++++++---------- lib/OnyxUtils.ts | 47 +++++++++++++++++++++++ lib/dependencies/ModuleProxy.ts | 39 +++++++++++++++++++ lib/dependencies/PerformanceProxy.ts | 13 +++++++ lib/metrics.ts | 56 ++++++++++++++++------------ 6 files changed, 193 insertions(+), 42 deletions(-) create mode 100644 lib/GlobalSettings.ts create mode 100644 lib/dependencies/ModuleProxy.ts create mode 100644 lib/dependencies/PerformanceProxy.ts diff --git a/lib/GlobalSettings.ts b/lib/GlobalSettings.ts new file mode 100644 index 000000000..f72ba14b2 --- /dev/null +++ b/lib/GlobalSettings.ts @@ -0,0 +1,34 @@ +/** + * Stores settings from Onyx.init globally so they can be made accessible by other parts of the library. + */ + +type GlobalSettings = { + enablePerformanceMetrics: boolean; +}; + +const globalSettings: GlobalSettings = { + enablePerformanceMetrics: false, +}; + +const listeners = new Set<(settings: GlobalSettings) => unknown>(); +function addGlobalSettingsChangeListener(listener: (settings: GlobalSettings) => unknown) { + listeners.add(listener); + return () => { + listeners.delete(listener); + }; +} + +function notifyListeners() { + listeners.forEach((listener) => listener(globalSettings)); +} + +function setPerformanceMetricsEnabled(enabled: boolean) { + globalSettings.enablePerformanceMetrics = enabled; + notifyListeners(); +} + +function isPerformanceMetricsEnabled() { + return globalSettings.enablePerformanceMetrics; +} + +export {setPerformanceMetricsEnabled, isPerformanceMetricsEnabled, addGlobalSettingsChangeListener}; diff --git a/lib/Onyx.ts b/lib/Onyx.ts index 14de5fb70..ff6a821b6 100644 --- a/lib/Onyx.ts +++ b/lib/Onyx.ts @@ -31,6 +31,8 @@ import OnyxUtils from './OnyxUtils'; import logMessages from './logMessages'; import type {Connection} from './OnyxConnectionManager'; import connectionManager from './OnyxConnectionManager'; +import * as GlobalSettings from './GlobalSettings'; +import decorateWithMetrics from './metrics'; /** Initialize the store with actions and listening for storage events */ function init({ @@ -42,6 +44,11 @@ function init({ debugSetState = false, enablePerformanceMetrics = false, }: InitOptions): void { + if (enablePerformanceMetrics) { + GlobalSettings.setPerformanceMetricsEnabled(true); + applyDecorators(); + } + Storage.init(); if (shouldSyncMultipleInstances) { @@ -66,24 +73,6 @@ function init({ Promise.all([OnyxUtils.addAllSafeEvictionKeysToRecentlyAccessedList(), OnyxUtils.initializeWithDefaultKeyStates()]).then(OnyxUtils.getDeferredInitTask().resolve); } -function applyDecorators() { - // We're requiring the script dynamically here so that it's only evaluated when decorators are used - // eslint-disable-next-line @typescript-eslint/no-var-requires - const decorate = require('./metrics'); - - // Re-assign with decorated functions - /* eslint-disable no-func-assign */ - connect = decorate(connect, 'Onyx:connect'); - set = decorate(set, 'Onyx:set'); - multiSet = decorate(multiSet, 'Onyx:multiSet'); - clear = decorate(clear, 'Onyx:clear'); - merge = decorate(merge, 'Onyx:merge'); - mergeCollection = decorate(mergeCollection, 'Onyx:mergeCollection'); - update = decorate(update, 'Onyx:update'); - clear = decorate(clear, 'Onyx:clear'); - /* eslint-enable */ -} - /** * Connects to an Onyx key given the options passed and listens to its changes. * @@ -759,7 +748,26 @@ const Onyx = { clear, init, registerLogger: Logger.registerLogger, -} as const; +}; + +function applyDecorators() { + /* eslint-disable rulesdir/prefer-actions-set-data */ + // @ts-expect-error Reassign + connect = decorateWithMetrics(connect, 'Onyx:connect'); + // @ts-expect-error Reassign + set = decorateWithMetrics(set, 'Onyx:set'); + // @ts-expect-error Reassign + multiSet = decorateWithMetrics(multiSet, 'Onyx:multiSet'); + // @ts-expect-error Reassign + merge = decorateWithMetrics(merge, 'Onyx:merge'); + // @ts-expect-error Reassign + mergeCollection = decorateWithMetrics(mergeCollection, 'Onyx:mergeCollection'); + // @ts-expect-error Reassign + update = decorateWithMetrics(update, 'Onyx:update'); + // @ts-expect-error Reassign + clear = decorateWithMetrics(clear, 'Onyx:clear'); + /* eslint-enable rulesdir/prefer-actions-set-data */ +} export default Onyx; export type {OnyxUpdate, Mapping, ConnectOptions}; diff --git a/lib/OnyxUtils.ts b/lib/OnyxUtils.ts index de89a230f..f94a25b0c 100644 --- a/lib/OnyxUtils.ts +++ b/lib/OnyxUtils.ts @@ -32,6 +32,8 @@ import utils from './utils'; import type {WithOnyxState} from './withOnyx/types'; import type {DeferredTask} from './createDeferredTask'; import createDeferredTask from './createDeferredTask'; +import * as GlobalSettings from './GlobalSettings'; +import decorateWithMetrics from './metrics'; // Method constants const METHOD = { @@ -1417,4 +1419,49 @@ const OnyxUtils = { getEvictionBlocklist, }; +GlobalSettings.addGlobalSettingsChangeListener(({enablePerformanceMetrics}) => { + if (!enablePerformanceMetrics) { + return; + } + + // @ts-expect-error Reassign + initStoreValues = decorateWithMetrics(initStoreValues, 'OnyxUtils.initStoreValues'); + // @ts-expect-error Reassign + maybeFlushBatchUpdates = decorateWithMetrics(maybeFlushBatchUpdates, 'OnyxUtils.maybeFlushBatchUpdates'); + // @ts-expect-error Reassign + batchUpdates = decorateWithMetrics(batchUpdates, 'OnyxUtils.batchUpdates'); + // @ts-expect-error Complex type signature + get = decorateWithMetrics(get, 'OnyxUtils.get'); + // @ts-expect-error Reassign + getAllKeys = decorateWithMetrics(getAllKeys, 'OnyxUtils.getAllKeys'); + // @ts-expect-error Reassign + getCollectionKeys = decorateWithMetrics(getCollectionKeys, 'OnyxUtils.getCollectionKeys'); + // @ts-expect-error Reassign + addAllSafeEvictionKeysToRecentlyAccessedList = decorateWithMetrics(addAllSafeEvictionKeysToRecentlyAccessedList, 'OnyxUtils.addAllSafeEvictionKeysToRecentlyAccessedList'); + // @ts-expect-error Reassign + keysChanged = decorateWithMetrics(keysChanged, 'OnyxUtils.keysChanged'); + // @ts-expect-error Reassign + keyChanged = decorateWithMetrics(keyChanged, 'OnyxUtils.keyChanged'); + // @ts-expect-error Reassign + sendDataToConnection = decorateWithMetrics(sendDataToConnection, 'OnyxUtils.sendDataToConnection'); + // @ts-expect-error Reassign + scheduleSubscriberUpdate = decorateWithMetrics(scheduleSubscriberUpdate, 'OnyxUtils.scheduleSubscriberUpdate'); + // @ts-expect-error Reassign + scheduleNotifyCollectionSubscribers = decorateWithMetrics(scheduleNotifyCollectionSubscribers, 'OnyxUtils.scheduleNotifyCollectionSubscribers'); + // @ts-expect-error Reassign + remove = decorateWithMetrics(remove, 'OnyxUtils.remove'); + // @ts-expect-error Reassign + reportStorageQuota = decorateWithMetrics(reportStorageQuota, 'OnyxUtils.reportStorageQuota'); + // @ts-expect-error Complex type signature + evictStorageAndRetry = decorateWithMetrics(evictStorageAndRetry, 'OnyxUtils.evictStorageAndRetry'); + // @ts-expect-error Reassign + broadcastUpdate = decorateWithMetrics(broadcastUpdate, 'OnyxUtils.broadcastUpdate'); + // @ts-expect-error Reassign + initializeWithDefaultKeyStates = decorateWithMetrics(initializeWithDefaultKeyStates, 'OnyxUtils.initializeWithDefaultKeyStates'); + // @ts-expect-error Complex type signature + multiGet = decorateWithMetrics(multiGet, 'OnyxUtils.multiGet'); + // @ts-expect-error Reassign + subscribeToKey = decorateWithMetrics(subscribeToKey, 'OnyxUtils.subscribeToKey'); +}); + export default OnyxUtils; diff --git a/lib/dependencies/ModuleProxy.ts b/lib/dependencies/ModuleProxy.ts new file mode 100644 index 000000000..597f38a81 --- /dev/null +++ b/lib/dependencies/ModuleProxy.ts @@ -0,0 +1,39 @@ +type ImportType = ReturnType; + +/** + * Create a lazily-imported module proxy. + * This is useful for lazily requiring optional dependencies. + */ +const createModuleProxy = (getModule: () => ImportType): TModule => { + const holder: {module: TModule | undefined} = {module: undefined}; + + const proxy = new Proxy(holder, { + get: (target, property) => { + if (property === '$$typeof') { + // If inlineRequires is enabled, Metro will look up all imports + // with the $$typeof operator. In this case, this will throw the + // `OptionalDependencyNotInstalledError` error because we try to access the module + // even though we are not using it (Metro does it), so instead we return undefined + // to bail out of inlineRequires here. + return undefined; + } + + if (target.module == null) { + // lazy initialize module via require() + // caller needs to make sure the require() call is wrapped in a try/catch + // eslint-disable-next-line no-param-reassign + target.module = getModule() as TModule; + } + return target.module[property as keyof typeof holder.module]; + }, + }); + return proxy as unknown as TModule; +}; + +class OptionalDependencyNotInstalledError extends Error { + constructor(name: string) { + super(`${name} is not installed!`); + } +} + +export {createModuleProxy, OptionalDependencyNotInstalledError}; diff --git a/lib/dependencies/PerformanceProxy.ts b/lib/dependencies/PerformanceProxy.ts new file mode 100644 index 000000000..1f15458f3 --- /dev/null +++ b/lib/dependencies/PerformanceProxy.ts @@ -0,0 +1,13 @@ +import type performance from 'react-native-performance'; +import {createModuleProxy, OptionalDependencyNotInstalledError} from './ModuleProxy'; + +const PerformanceProxy = createModuleProxy(() => { + try { + // eslint-disable-next-line @typescript-eslint/no-var-requires + return require('react-native-performance').default; + } catch { + throw new OptionalDependencyNotInstalledError('react-native-performance'); + } +}); + +export default PerformanceProxy; diff --git a/lib/metrics.ts b/lib/metrics.ts index 341f0cd16..f6cb33491 100644 --- a/lib/metrics.ts +++ b/lib/metrics.ts @@ -1,47 +1,57 @@ -import performance from 'react-native-performance'; -import type {PerformanceMark} from 'react-native-performance'; +import type * as performance from 'react-native-performance'; +import PerformanceProxy from './dependencies/PerformanceProxy'; const decoratedAliases = new Set(); /** * Capture a measurement between the start mark and now */ -function measureMarkToNow(startMark: PerformanceMark, detail: Record) { - performance.measure(`${startMark.name} [${startMark.detail.args.toString()}]`, { +function measureMarkToNow(startMark: performance.PerformanceMark, detail: Record) { + PerformanceProxy.measure(`${startMark.name} [${startMark.detail.args.toString()}]`, { start: startMark.startTime, - end: performance.now(), + end: PerformanceProxy.now(), detail: {...startMark.detail, ...detail}, }); } +function isPromiseLike(value: unknown): value is Promise { + return value != null && typeof value === 'object' && 'then' in value; +} + /** * Wraps a function with metrics capturing logic */ -function decorateWithMetrics>(func: (...args: Args) => ReturnType, alias = func.name) { +function decorateWithMetrics(func: (...args: Args) => ReturnType, alias = func.name) { if (decoratedAliases.has(alias)) { throw new Error(`"${alias}" is already decorated`); } decoratedAliases.add(alias); function decorated(...args: Args) { - const mark = performance.mark(alias, {detail: {args, alias}}); - - const originalPromise = func(...args); - - /* - * The handlers added here are not affecting the original promise - * They create a separate chain that's not exposed (returned) to the original caller - */ - originalPromise - .then((result) => { - measureMarkToNow(mark, {result}); - }) - .catch((error) => { - measureMarkToNow(mark, {error}); - }); - - return originalPromise; + const mark = PerformanceProxy.mark(alias, {detail: {args, alias}}); + + const originalReturnValue = func(...args); + + if (isPromiseLike(originalReturnValue)) { + /* + * The handlers added here are not affecting the original promise + * They create a separate chain that's not exposed (returned) to the original caller + */ + originalReturnValue + .then((result) => { + measureMarkToNow(mark, {result}); + }) + .catch((error) => { + measureMarkToNow(mark, {error}); + }); + + return originalReturnValue; + } + + measureMarkToNow(mark, {result: originalReturnValue}); + return originalReturnValue; } + decorated.name = `${alias}_DECORATED`; return decorated; } From 65c157170091efac41f6d8b7327680c6e503c668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Wed, 20 Nov 2024 16:36:22 +0100 Subject: [PATCH 3/6] decorate storage as well --- lib/Onyx.ts | 15 ++++++++------- lib/OnyxUtils.ts | 1 + lib/storage/index.ts | 24 ++++++++++++++++++++++-- 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/lib/Onyx.ts b/lib/Onyx.ts index ff6a821b6..5b3dbd0e7 100644 --- a/lib/Onyx.ts +++ b/lib/Onyx.ts @@ -751,21 +751,22 @@ const Onyx = { }; function applyDecorators() { + // We are reassigning the functions directly so that internal function calls are also decorated /* eslint-disable rulesdir/prefer-actions-set-data */ // @ts-expect-error Reassign - connect = decorateWithMetrics(connect, 'Onyx:connect'); + connect = decorateWithMetrics(connect, 'Onyx.connect'); // @ts-expect-error Reassign - set = decorateWithMetrics(set, 'Onyx:set'); + set = decorateWithMetrics(set, 'Onyx.set'); // @ts-expect-error Reassign - multiSet = decorateWithMetrics(multiSet, 'Onyx:multiSet'); + multiSet = decorateWithMetrics(multiSet, 'Onyx.multiSet'); // @ts-expect-error Reassign - merge = decorateWithMetrics(merge, 'Onyx:merge'); + merge = decorateWithMetrics(merge, 'Onyx.merge'); // @ts-expect-error Reassign - mergeCollection = decorateWithMetrics(mergeCollection, 'Onyx:mergeCollection'); + mergeCollection = decorateWithMetrics(mergeCollection, 'Onyx.mergeCollection'); // @ts-expect-error Reassign - update = decorateWithMetrics(update, 'Onyx:update'); + update = decorateWithMetrics(update, 'Onyx.update'); // @ts-expect-error Reassign - clear = decorateWithMetrics(clear, 'Onyx:clear'); + clear = decorateWithMetrics(clear, 'Onyx.clear'); /* eslint-enable rulesdir/prefer-actions-set-data */ } diff --git a/lib/OnyxUtils.ts b/lib/OnyxUtils.ts index f94a25b0c..891c90659 100644 --- a/lib/OnyxUtils.ts +++ b/lib/OnyxUtils.ts @@ -1423,6 +1423,7 @@ GlobalSettings.addGlobalSettingsChangeListener(({enablePerformanceMetrics}) => { if (!enablePerformanceMetrics) { return; } + // We are reassigning the functions directly so that internal function calls are also decorated // @ts-expect-error Reassign initStoreValues = decorateWithMetrics(initStoreValues, 'OnyxUtils.initStoreValues'); diff --git a/lib/storage/index.ts b/lib/storage/index.ts index c9b797b10..938b615a5 100644 --- a/lib/storage/index.ts +++ b/lib/storage/index.ts @@ -4,6 +4,8 @@ import PlatformStorage from './platforms'; import InstanceSync from './InstanceSync'; import MemoryOnlyProvider from './providers/MemoryOnlyProvider'; import type StorageProvider from './providers/types'; +import * as GlobalSettings from '../GlobalSettings'; +import decorateWithMetrics from '../metrics'; let provider = PlatformStorage; let shouldKeepInstancesSync = false; @@ -55,7 +57,7 @@ function tryOrDegradePerformance(fn: () => Promise | T, waitForInitializat }); } -const Storage: Storage = { +const storage: Storage = { /** * Returns the storage provider currently in use */ @@ -202,4 +204,22 @@ const Storage: Storage = { }, }; -export default Storage; +GlobalSettings.addGlobalSettingsChangeListener(({enablePerformanceMetrics}) => { + if (!enablePerformanceMetrics) { + return; + } + + // Apply decorators + storage.getItem = decorateWithMetrics(storage.getItem, 'Storage.getItem'); + storage.multiGet = decorateWithMetrics(storage.multiGet, 'Storage.multiGet'); + storage.setItem = decorateWithMetrics(storage.setItem, 'Storage.setItem'); + storage.multiSet = decorateWithMetrics(storage.multiSet, 'Storage.multiSet'); + storage.mergeItem = decorateWithMetrics(storage.mergeItem, 'Storage.mergeItem'); + storage.multiMerge = decorateWithMetrics(storage.multiMerge, 'Storage.multiMerge'); + storage.removeItem = decorateWithMetrics(storage.removeItem, 'Storage.removeItem'); + storage.removeItems = decorateWithMetrics(storage.removeItems, 'Storage.removeItems'); + storage.clear = decorateWithMetrics(storage.clear, 'Storage.clear'); + storage.getAllKeys = decorateWithMetrics(storage.getAllKeys, 'Storage.getAllKeys'); +}); + +export default storage; From 2578654d9844a065a15f95e11733e0643191a5a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Wed, 20 Nov 2024 16:39:13 +0100 Subject: [PATCH 4/6] remove example --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 5592c6d47..a46d06d84 100644 --- a/.gitignore +++ b/.gitignore @@ -21,5 +21,3 @@ yalc.lock # Perf tests .reassure - -example/ \ No newline at end of file From 0494c31ba653c8dbb582657d53103bc70a49e7a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Wed, 20 Nov 2024 16:50:13 +0100 Subject: [PATCH 5/6] provide web impl --- .../{PerformanceProxy.ts => PerformanceProxy/index.native.ts} | 2 +- lib/dependencies/PerformanceProxy/index.ts | 2 ++ lib/metrics.ts | 3 +-- 3 files changed, 4 insertions(+), 3 deletions(-) rename lib/dependencies/{PerformanceProxy.ts => PerformanceProxy/index.native.ts} (95%) create mode 100644 lib/dependencies/PerformanceProxy/index.ts diff --git a/lib/dependencies/PerformanceProxy.ts b/lib/dependencies/PerformanceProxy/index.native.ts similarity index 95% rename from lib/dependencies/PerformanceProxy.ts rename to lib/dependencies/PerformanceProxy/index.native.ts index 1f15458f3..da35d4199 100644 --- a/lib/dependencies/PerformanceProxy.ts +++ b/lib/dependencies/PerformanceProxy/index.native.ts @@ -1,5 +1,5 @@ import type performance from 'react-native-performance'; -import {createModuleProxy, OptionalDependencyNotInstalledError} from './ModuleProxy'; +import {createModuleProxy, OptionalDependencyNotInstalledError} from '../ModuleProxy'; const PerformanceProxy = createModuleProxy(() => { try { diff --git a/lib/dependencies/PerformanceProxy/index.ts b/lib/dependencies/PerformanceProxy/index.ts new file mode 100644 index 000000000..3aff0ad43 --- /dev/null +++ b/lib/dependencies/PerformanceProxy/index.ts @@ -0,0 +1,2 @@ +// Use the existing performance API on web +export default performance; diff --git a/lib/metrics.ts b/lib/metrics.ts index f6cb33491..301a54678 100644 --- a/lib/metrics.ts +++ b/lib/metrics.ts @@ -1,4 +1,3 @@ -import type * as performance from 'react-native-performance'; import PerformanceProxy from './dependencies/PerformanceProxy'; const decoratedAliases = new Set(); @@ -6,7 +5,7 @@ const decoratedAliases = new Set(); /** * Capture a measurement between the start mark and now */ -function measureMarkToNow(startMark: performance.PerformanceMark, detail: Record) { +function measureMarkToNow(startMark: PerformanceMark, detail: Record) { PerformanceProxy.measure(`${startMark.name} [${startMark.detail.args.toString()}]`, { start: startMark.startTime, end: PerformanceProxy.now(), From 42055a00e5666ac01cb377becfbda33fd270a38e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Wed, 27 Nov 2024 21:13:17 +0100 Subject: [PATCH 6/6] use typeof --- lib/GlobalSettings.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/GlobalSettings.ts b/lib/GlobalSettings.ts index f72ba14b2..68617b7ed 100644 --- a/lib/GlobalSettings.ts +++ b/lib/GlobalSettings.ts @@ -2,14 +2,12 @@ * Stores settings from Onyx.init globally so they can be made accessible by other parts of the library. */ -type GlobalSettings = { - enablePerformanceMetrics: boolean; -}; - -const globalSettings: GlobalSettings = { +const globalSettings = { enablePerformanceMetrics: false, }; +type GlobalSettings = typeof globalSettings; + const listeners = new Set<(settings: GlobalSettings) => unknown>(); function addGlobalSettingsChangeListener(listener: (settings: GlobalSettings) => unknown) { listeners.add(listener);