@rozenite/performance-monitor-plugin 1.0.0-alpha.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +130 -0
  3. package/dist/App.html +31 -0
  4. package/dist/assets/App-C1ubeKf9.js +119 -0
  5. package/dist/assets/App-DRvEE1L4.css +1 -0
  6. package/dist/react-native.cjs +1 -0
  7. package/dist/react-native.d.ts +1 -0
  8. package/dist/react-native.js +5 -0
  9. package/dist/rozenite.config.d.ts +7 -0
  10. package/dist/rozenite.json +1 -0
  11. package/dist/src/react-native/asserts.d.ts +4 -0
  12. package/dist/src/react-native/helpers.d.ts +1 -0
  13. package/dist/src/react-native/performance-monitor.d.ts +8 -0
  14. package/dist/src/react-native/usePerformanceMonitorDevTools.d.ts +1 -0
  15. package/dist/src/shared/types.d.ts +39 -0
  16. package/dist/src/ui/App.d.ts +1 -0
  17. package/dist/src/ui/components/DataTable.d.ts +8 -0
  18. package/dist/src/ui/components/DetailsDisplay.d.ts +4 -0
  19. package/dist/src/ui/components/DetailsSidebar.d.ts +6 -0
  20. package/dist/src/ui/components/ExportModal.d.ts +9 -0
  21. package/dist/src/ui/components/JsonTree.d.ts +4 -0
  22. package/dist/src/ui/components/MarkDetails.d.ts +5 -0
  23. package/dist/src/ui/components/MarksTable.d.ts +6 -0
  24. package/dist/src/ui/components/MeasureDetails.d.ts +5 -0
  25. package/dist/src/ui/components/MeasuresTable.d.ts +6 -0
  26. package/dist/src/ui/components/MetricDetails.d.ts +5 -0
  27. package/dist/src/ui/components/MetricsTable.d.ts +6 -0
  28. package/dist/src/ui/components/SessionDuration.d.ts +5 -0
  29. package/dist/src/ui/utils.d.ts +2 -0
  30. package/dist/usePerformanceMonitorDevTools.cjs +1 -0
  31. package/dist/usePerformanceMonitorDevTools.js +118 -0
  32. package/package.json +41 -0
  33. package/project.json +12 -0
  34. package/react-native.ts +8 -0
  35. package/rozenite.config.ts +8 -0
  36. package/src/react-native/asserts.ts +29 -0
  37. package/src/react-native/helpers.ts +4 -0
  38. package/src/react-native/performance-monitor.ts +171 -0
  39. package/src/react-native/usePerformanceMonitorDevTools.ts +31 -0
  40. package/src/shared/types.ts +50 -0
  41. package/src/ui/App.css +97 -0
  42. package/src/ui/App.tsx +286 -0
  43. package/src/ui/components/DataTable.tsx +117 -0
  44. package/src/ui/components/DetailsDisplay.tsx +26 -0
  45. package/src/ui/components/DetailsSidebar.tsx +87 -0
  46. package/src/ui/components/ExportModal.tsx +278 -0
  47. package/src/ui/components/JsonTree.tsx +35 -0
  48. package/src/ui/components/MarkDetails.tsx +45 -0
  49. package/src/ui/components/MarksTable.tsx +42 -0
  50. package/src/ui/components/MeasureDetails.tsx +74 -0
  51. package/src/ui/components/MeasuresTable.tsx +72 -0
  52. package/src/ui/components/MetricDetails.tsx +56 -0
  53. package/src/ui/components/MetricsTable.tsx +54 -0
  54. package/src/ui/components/SessionDuration.tsx +54 -0
  55. package/src/ui/utils.ts +17 -0
  56. package/tsconfig.json +32 -0
  57. package/tsconfig.tsbuildinfo +1 -0
  58. package/vite.config.ts +20 -0
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});exports.usePerformanceMonitorDevTools=void 0;process.env.NODE_ENV!=="production"?exports.usePerformanceMonitorDevTools=require("./usePerformanceMonitorDevTools.cjs").usePerformanceMonitorDevTools:exports.usePerformanceMonitorDevTools=()=>null;
@@ -0,0 +1 @@
1
+ export declare let usePerformanceMonitorDevTools: typeof import('./src/react-native/usePerformanceMonitorDevTools').usePerformanceMonitorDevTools;
@@ -0,0 +1,5 @@
1
+ let e;
2
+ process.env.NODE_ENV !== "production" ? e = require("./usePerformanceMonitorDevTools.js").usePerformanceMonitorDevTools : e = () => null;
3
+ export {
4
+ e as usePerformanceMonitorDevTools
5
+ };
@@ -0,0 +1,7 @@
1
+ declare const _default: {
2
+ panels: {
3
+ name: string;
4
+ source: string;
5
+ }[];
6
+ };
7
+ export default _default;
@@ -0,0 +1 @@
1
+ {"name":"@rozenite/performance-monitor-plugin","version":"1.0.0-alpha.10","description":"Performance Monitor for Rozenite.","panels":[{"name":"Performance Monitor","source":"/App.html"}]}
@@ -0,0 +1,4 @@
1
+ import { PerformanceMark, PerformanceMeasure, PerformanceMetric } from 'react-native-performance';
2
+ export declare function assertPerformanceMark(entry: PerformanceEntry): asserts entry is PerformanceMark;
3
+ export declare function assertPerformanceMeasure(entry: PerformanceEntry): asserts entry is PerformanceMeasure;
4
+ export declare function assertPerformanceMetric(entry: PerformanceEntry): asserts entry is PerformanceMetric;
@@ -0,0 +1 @@
1
+ export declare const toDateTimestamp: (origin: number, startTime: number) => number;
@@ -0,0 +1,8 @@
1
+ import { PerformanceMonitorDevToolsClient } from '../shared/types';
2
+ export type PerformanceMonitor = {
3
+ enable: () => void;
4
+ disable: () => void;
5
+ isEnabled: () => boolean;
6
+ dispose: () => void;
7
+ };
8
+ export declare const getPerformanceMonitor: (client: PerformanceMonitorDevToolsClient) => PerformanceMonitor;
@@ -0,0 +1 @@
1
+ export declare const usePerformanceMonitorDevTools: () => void;
@@ -0,0 +1,39 @@
1
+ import { RozeniteDevToolsClient } from '@rozenite/plugin-bridge';
2
+ export type SharedPerformanceEntryProperties = {
3
+ name: string;
4
+ startTime: number;
5
+ duration: number;
6
+ };
7
+ export type SerializedPerformanceMeasure = SharedPerformanceEntryProperties & {
8
+ entryType: 'measure';
9
+ detail?: unknown;
10
+ };
11
+ export type SerializedPerformanceMark = SharedPerformanceEntryProperties & {
12
+ entryType: 'mark';
13
+ detail?: unknown;
14
+ };
15
+ export type SerializedPerformanceMetric = SharedPerformanceEntryProperties & {
16
+ entryType: 'metric';
17
+ value: string | number;
18
+ detail?: unknown;
19
+ };
20
+ export type SerializedPerformanceEntry = SerializedPerformanceMeasure | SerializedPerformanceMark | SerializedPerformanceMetric;
21
+ export type PerformanceMonitorEventMap = {
22
+ setEnabled: {
23
+ enabled: boolean;
24
+ };
25
+ setSession: {
26
+ sessionStartedAt: number;
27
+ timeOrigin: number;
28
+ };
29
+ appendMeasures: {
30
+ measures: SerializedPerformanceMeasure[];
31
+ };
32
+ appendMarks: {
33
+ marks: SerializedPerformanceMark[];
34
+ };
35
+ setMetrics: {
36
+ metrics: SerializedPerformanceMetric[];
37
+ };
38
+ };
39
+ export type PerformanceMonitorDevToolsClient = RozeniteDevToolsClient<PerformanceMonitorEventMap>;
@@ -0,0 +1 @@
1
+ export default function PerformanceMonitorPanel(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,8 @@
1
+ import { ColumnDef } from '@tanstack/react-table';
2
+ export type DataTableProps<TData> = {
3
+ data: TData[];
4
+ columns: ColumnDef<TData>[];
5
+ onRowClick?: (item: TData) => void;
6
+ emptyMessage?: string;
7
+ };
8
+ export declare const DataTable: <TData>({ data, columns, onRowClick, emptyMessage, }: DataTableProps<TData>) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ export type DetailsDisplayProps = {
2
+ details?: unknown;
3
+ };
4
+ export declare const DetailsDisplay: ({ details }: DetailsDisplayProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { SerializedPerformanceEntry } from '../../shared/types';
2
+ export type DetailsSidebarProps = {
3
+ selectedItem: SerializedPerformanceEntry | null;
4
+ onClose: () => void;
5
+ };
6
+ export declare const DetailsSidebar: ({ selectedItem, onClose, }: DetailsSidebarProps) => import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,9 @@
1
+ import { SerializedPerformanceMeasure, SerializedPerformanceMark, SerializedPerformanceMetric } from '../../shared/types';
2
+ export type ExportModalProps = {
3
+ measures: SerializedPerformanceMeasure[];
4
+ metrics: SerializedPerformanceMetric[];
5
+ marks: SerializedPerformanceMark[];
6
+ sessionStartedAt: number;
7
+ clockShift: number;
8
+ };
9
+ export declare function ExportModal({ measures, metrics, marks, sessionStartedAt, clockShift, }: ExportModalProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,4 @@
1
+ export type JsonTreeProps = {
2
+ data: unknown;
3
+ };
4
+ export declare const JsonTree: ({ data }: JsonTreeProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { SerializedPerformanceMark } from '../../shared/types';
2
+ export type MarkDetailsProps = {
3
+ mark: SerializedPerformanceMark;
4
+ };
5
+ export declare const MarkDetails: ({ mark }: MarkDetailsProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { SerializedPerformanceMark } from '../../shared/types';
2
+ export type MarksTableProps = {
3
+ marks: SerializedPerformanceMark[];
4
+ onRowClick?: (mark: SerializedPerformanceMark) => void;
5
+ };
6
+ export declare const MarksTable: ({ marks, onRowClick }: MarksTableProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { SerializedPerformanceMeasure } from '../../shared/types';
2
+ export type MeasureDetailsProps = {
3
+ measure: SerializedPerformanceMeasure;
4
+ };
5
+ export declare const MeasureDetails: ({ measure }: MeasureDetailsProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { SerializedPerformanceMeasure } from '../../shared/types';
2
+ export type MeasuresTableProps = {
3
+ measures: SerializedPerformanceMeasure[];
4
+ onRowClick?: (measure: SerializedPerformanceMeasure) => void;
5
+ };
6
+ export declare const MeasuresTable: ({ measures, onRowClick }: MeasuresTableProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { SerializedPerformanceMetric } from '../../shared/types';
2
+ export type MetricDetailsProps = {
3
+ metric: SerializedPerformanceMetric;
4
+ };
5
+ export declare const MetricDetails: ({ metric }: MetricDetailsProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { SerializedPerformanceMetric } from '../../shared/types';
2
+ export type MetricsTableProps = {
3
+ metrics: SerializedPerformanceMetric[];
4
+ onRowClick?: (metric: SerializedPerformanceMetric) => void;
5
+ };
6
+ export declare const MetricsTable: ({ metrics, onRowClick }: MetricsTableProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ export type SessionDurationProps = {
2
+ isActive: boolean;
3
+ sessionStartedAt: number;
4
+ };
5
+ export declare const SessionDuration: ({ isActive, sessionStartedAt, }: SessionDurationProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ export declare const downloadFile: (data: unknown, filename: string) => Promise<void>;
2
+ export declare const formatTime: (timestamp: number) => string;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const T=require("@rozenite/plugin-bridge"),g=require("react"),M=require("react-native-performance"),E=e=>e&&e.__esModule?e:{default:e},a=E(M),m=(e,s)=>e-a.default.timeOrigin+s;function v(e){if(e.entryType!=="mark")throw new Error("Entry is not a PerformanceMark")}function P(e){if(e.entryType!=="measure")throw new Error("Entry is not a PerformanceMeasure")}function k(e){if(e.entryType!=="metric")throw new Error("Entry is not a PerformanceMetric")}const w=e=>{let s=[],o=0,n=0,d=!1;const f=(i,l)=>{const u=new M.PerformanceObserver(i);u.observe(l),s.push(u)},b=()=>{d=!0,n=Date.now(),o=m(n,a.default.now()),e.send("setSession",{sessionStartedAt:o,timeOrigin:a.default.timeOrigin});const i=t=>{e.send("appendMeasures",{measures:t})},l=t=>{e.send("appendMarks",{marks:t})},u=t=>{e.send("setMetrics",{metrics:t})};f(t=>{const r=t.getEntries().map(c=>(v(c),{name:c.name,startTime:m(n,c.startTime),duration:c.duration,entryType:"mark"}));l(r)},{type:"mark",buffered:!0}),f(t=>{i(t.getEntries().map(r=>(P(r),{name:r.name,startTime:m(n,r.startTime),duration:r.duration,entryType:"measure",detail:r.detail})))},{type:"measure",buffered:!0}),f(t=>{u(t.getEntries().map(r=>(k(r),{name:r.name,startTime:m(n,r.startTime),duration:r.duration,entryType:"metric",value:r.value,detail:r.detail})))},{type:"metric",buffered:!0})},p=()=>{s.forEach(i=>{i.disconnect()}),a.default.clearMarks(),a.default.clearMeasures(),a.default.clearMetrics(),s=[],d=!1,o=0,n=0};return{enable:b,disable:p,isEnabled:()=>d,dispose:()=>{p()}}},y=()=>{const e=T.useRozeniteDevToolsClient({pluginId:"@rozenite/performance-monitor-plugin"});g.useEffect(()=>{if(!e)return;const s=w(e),o=e.onMessage("setEnabled",({enabled:n})=>{n?s.enable():s.disable()});return()=>{o.remove(),s.dispose()}},[e])};exports.usePerformanceMonitorDevTools=y;
@@ -0,0 +1,118 @@
1
+ import { useRozeniteDevToolsClient as b } from "@rozenite/plugin-bridge";
2
+ import { useEffect as T } from "react";
3
+ import a, { PerformanceObserver as E } from "react-native-performance";
4
+ const u = (e, s) => e - a.timeOrigin + s;
5
+ function g(e) {
6
+ if (e.entryType !== "mark")
7
+ throw new Error("Entry is not a PerformanceMark");
8
+ }
9
+ function v(e) {
10
+ if (e.entryType !== "measure")
11
+ throw new Error("Entry is not a PerformanceMeasure");
12
+ }
13
+ function k(e) {
14
+ if (e.entryType !== "metric")
15
+ throw new Error("Entry is not a PerformanceMetric");
16
+ }
17
+ const w = (e) => {
18
+ let s = [], o = 0, n = 0, p = !1;
19
+ const d = (i, f) => {
20
+ const m = new E(i);
21
+ m.observe(f), s.push(m);
22
+ }, M = () => {
23
+ p = !0, n = Date.now(), o = u(n, a.now()), e.send("setSession", {
24
+ sessionStartedAt: o,
25
+ timeOrigin: a.timeOrigin
26
+ });
27
+ const i = (t) => {
28
+ e.send("appendMeasures", {
29
+ measures: t
30
+ });
31
+ }, f = (t) => {
32
+ e.send("appendMarks", {
33
+ marks: t
34
+ });
35
+ }, m = (t) => {
36
+ e.send("setMetrics", {
37
+ metrics: t
38
+ });
39
+ };
40
+ d(
41
+ (t) => {
42
+ const r = t.getEntries().map((c) => (g(c), {
43
+ name: c.name,
44
+ startTime: u(n, c.startTime),
45
+ duration: c.duration,
46
+ entryType: "mark"
47
+ }));
48
+ f(r);
49
+ },
50
+ {
51
+ type: "mark",
52
+ buffered: !0
53
+ }
54
+ ), d(
55
+ (t) => {
56
+ i(
57
+ t.getEntries().map((r) => (v(r), {
58
+ name: r.name,
59
+ startTime: u(n, r.startTime),
60
+ duration: r.duration,
61
+ entryType: "measure",
62
+ detail: r.detail
63
+ }))
64
+ );
65
+ },
66
+ {
67
+ type: "measure",
68
+ buffered: !0
69
+ }
70
+ ), d(
71
+ (t) => {
72
+ m(
73
+ t.getEntries().map((r) => (k(r), {
74
+ name: r.name,
75
+ startTime: u(n, r.startTime),
76
+ duration: r.duration,
77
+ entryType: "metric",
78
+ value: r.value,
79
+ detail: r.detail
80
+ }))
81
+ );
82
+ },
83
+ {
84
+ type: "metric",
85
+ buffered: !0
86
+ }
87
+ );
88
+ }, l = () => {
89
+ s.forEach((i) => {
90
+ i.disconnect();
91
+ }), a.clearMarks(), a.clearMeasures(), a.clearMetrics(), s = [], p = !1, o = 0, n = 0;
92
+ };
93
+ return {
94
+ enable: M,
95
+ disable: l,
96
+ isEnabled: () => p,
97
+ dispose: () => {
98
+ l();
99
+ }
100
+ };
101
+ }, z = () => {
102
+ const e = b({
103
+ pluginId: "@rozenite/performance-monitor-plugin"
104
+ });
105
+ T(() => {
106
+ if (!e)
107
+ return;
108
+ const s = w(e), o = e.onMessage("setEnabled", ({ enabled: n }) => {
109
+ n ? s.enable() : s.disable();
110
+ });
111
+ return () => {
112
+ o.remove(), s.dispose();
113
+ };
114
+ }, [e]);
115
+ };
116
+ export {
117
+ z as usePerformanceMonitorDevTools
118
+ };
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@rozenite/performance-monitor-plugin",
3
+ "version": "1.0.0-alpha.11",
4
+ "description": "Performance Monitor for Rozenite.",
5
+ "type": "module",
6
+ "main": "./dist/react-native.cjs",
7
+ "module": "./dist/react-native.js",
8
+ "types": "./dist/react-native.d.ts",
9
+ "dependencies": {
10
+ "@rozenite/plugin-bridge": "1.0.0-alpha.11"
11
+ },
12
+ "devDependencies": {
13
+ "@radix-ui/react-icons": "^1.3.2",
14
+ "@radix-ui/react-separator": "^1.1.7",
15
+ "@radix-ui/react-tabs": "^1.1.12",
16
+ "@radix-ui/themes": "^3.2.1",
17
+ "@tanstack/react-table": "^8.21.3",
18
+ "react-virtuoso": "^4.6.0",
19
+ "@types/react": "~18.3.12",
20
+ "react": "18.3.1",
21
+ "react-dom": "18.3.0",
22
+ "react-json-tree": "^0.20.0",
23
+ "react-native": "0.76.0",
24
+ "react-native-performance": "5.1.4",
25
+ "react-native-web": "0.21.0",
26
+ "typescript": "^5.7.3",
27
+ "vite": "^6.0.0",
28
+ "@rozenite/vite-plugin": "1.0.0-alpha.11",
29
+ "rozenite": "1.0.0-alpha.11"
30
+ },
31
+ "peerDependencies": {
32
+ "react": "*",
33
+ "react-native": "*",
34
+ "react-native-performance": "*"
35
+ },
36
+ "license": "MIT",
37
+ "scripts": {
38
+ "build": "rozenite build",
39
+ "dev": "rozenite dev"
40
+ }
41
+ }
package/project.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
3
+ "name": "@rozenite/performance-monitor-plugin",
4
+ "targets": {
5
+ "build": {
6
+ "cache": true,
7
+ "dependsOn": ["^build"],
8
+ "inputs": ["{projectRoot}/src/**/*"],
9
+ "outputs": ["{projectRoot}/dist"]
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,8 @@
1
+ export let usePerformanceMonitorDevTools: typeof import('./src/react-native/usePerformanceMonitorDevTools').usePerformanceMonitorDevTools;
2
+
3
+ if (process.env.NODE_ENV !== 'production') {
4
+ usePerformanceMonitorDevTools =
5
+ require('./src/react-native/usePerformanceMonitorDevTools').usePerformanceMonitorDevTools;
6
+ } else {
7
+ usePerformanceMonitorDevTools = () => null;
8
+ }
@@ -0,0 +1,8 @@
1
+ export default {
2
+ panels: [
3
+ {
4
+ name: 'Performance Monitor',
5
+ source: './src/ui/App.tsx',
6
+ },
7
+ ],
8
+ };
@@ -0,0 +1,29 @@
1
+ import type {
2
+ PerformanceMark,
3
+ PerformanceMeasure,
4
+ PerformanceMetric,
5
+ } from 'react-native-performance';
6
+
7
+ export function assertPerformanceMark(
8
+ entry: PerformanceEntry
9
+ ): asserts entry is PerformanceMark {
10
+ if (entry.entryType !== 'mark') {
11
+ throw new Error('Entry is not a PerformanceMark');
12
+ }
13
+ }
14
+
15
+ export function assertPerformanceMeasure(
16
+ entry: PerformanceEntry
17
+ ): asserts entry is PerformanceMeasure {
18
+ if (entry.entryType !== 'measure') {
19
+ throw new Error('Entry is not a PerformanceMeasure');
20
+ }
21
+ }
22
+
23
+ export function assertPerformanceMetric(
24
+ entry: PerformanceEntry
25
+ ): asserts entry is PerformanceMetric {
26
+ if (entry.entryType !== 'metric') {
27
+ throw new Error('Entry is not a PerformanceMetric');
28
+ }
29
+ }
@@ -0,0 +1,4 @@
1
+ import performance from 'react-native-performance';
2
+
3
+ export const toDateTimestamp = (origin: number, startTime: number): number =>
4
+ origin - performance.timeOrigin + startTime;
@@ -0,0 +1,171 @@
1
+ import performance, {
2
+ EntryType,
3
+ PerformanceEntry,
4
+ PerformanceObserver,
5
+ } from 'react-native-performance';
6
+ import type {
7
+ PerformanceMonitorDevToolsClient,
8
+ SerializedPerformanceMark,
9
+ SerializedPerformanceMeasure,
10
+ SerializedPerformanceMetric,
11
+ } from '../shared/types';
12
+ import { toDateTimestamp } from './helpers';
13
+ import {
14
+ assertPerformanceMark,
15
+ assertPerformanceMeasure,
16
+ assertPerformanceMetric,
17
+ } from './asserts';
18
+
19
+ type PerformanceObserverOptions = { type: EntryType; buffered?: boolean };
20
+
21
+ type PerformanceObserverEntryList = {
22
+ entries: PerformanceEntry[];
23
+ getEntries(): PerformanceEntry[];
24
+ getEntriesByType(type: EntryType): PerformanceEntry[];
25
+ getEntriesByName(name: string, type?: EntryType): PerformanceEntry[];
26
+ };
27
+
28
+ type PerformanceObserverCallback = (
29
+ list: PerformanceObserverEntryList,
30
+ observer: PerformanceObserver
31
+ ) => void;
32
+
33
+ export type PerformanceMonitor = {
34
+ enable: () => void;
35
+ disable: () => void;
36
+ isEnabled: () => boolean;
37
+ dispose: () => void;
38
+ };
39
+
40
+ export const getPerformanceMonitor = (
41
+ client: PerformanceMonitorDevToolsClient
42
+ ): PerformanceMonitor => {
43
+ let observers: PerformanceObserver[] = [];
44
+ let sessionStartedAt = 0;
45
+ let origin = 0;
46
+ let isObserving = false;
47
+
48
+ const addObserver = (
49
+ callback: PerformanceObserverCallback,
50
+ options: PerformanceObserverOptions
51
+ ) => {
52
+ const observer = new PerformanceObserver(callback);
53
+ observer.observe(options);
54
+ observers.push(observer);
55
+ };
56
+
57
+ const enable = (): void => {
58
+ isObserving = true;
59
+ origin = Date.now();
60
+ sessionStartedAt = toDateTimestamp(origin, performance.now());
61
+ client.send('setSession', {
62
+ sessionStartedAt,
63
+ timeOrigin: performance.timeOrigin,
64
+ });
65
+
66
+ const appendMeasures = (measures: SerializedPerformanceMeasure[]) => {
67
+ client.send('appendMeasures', {
68
+ measures,
69
+ });
70
+ };
71
+
72
+ const appendMarks = (marks: SerializedPerformanceMark[]) => {
73
+ client.send('appendMarks', {
74
+ marks,
75
+ });
76
+ };
77
+
78
+ const setMetrics = (metrics: SerializedPerformanceMetric[]) => {
79
+ client.send('setMetrics', {
80
+ metrics,
81
+ });
82
+ };
83
+
84
+ addObserver(
85
+ (list) => {
86
+ const marks = list.getEntries().map((entry) => {
87
+ assertPerformanceMark(entry);
88
+
89
+ return {
90
+ name: entry.name,
91
+ startTime: toDateTimestamp(origin, entry.startTime),
92
+ duration: entry.duration,
93
+ entryType: 'mark' as const,
94
+ };
95
+ });
96
+
97
+ appendMarks(marks);
98
+ },
99
+ {
100
+ type: 'mark',
101
+ buffered: true,
102
+ }
103
+ );
104
+ addObserver(
105
+ (list) => {
106
+ appendMeasures(
107
+ list.getEntries().map((entry) => {
108
+ assertPerformanceMeasure(entry);
109
+
110
+ return {
111
+ name: entry.name,
112
+ startTime: toDateTimestamp(origin, entry.startTime),
113
+ duration: entry.duration,
114
+ entryType: 'measure' as const,
115
+ detail: entry.detail,
116
+ };
117
+ })
118
+ );
119
+ },
120
+ {
121
+ type: 'measure',
122
+ buffered: true,
123
+ }
124
+ );
125
+ addObserver(
126
+ (list) => {
127
+ setMetrics(
128
+ list.getEntries().map((entry) => {
129
+ assertPerformanceMetric(entry);
130
+
131
+ return {
132
+ name: entry.name,
133
+ startTime: toDateTimestamp(origin, entry.startTime),
134
+ duration: entry.duration,
135
+ entryType: 'metric' as const,
136
+ value: entry.value,
137
+ detail: entry.detail,
138
+ };
139
+ })
140
+ );
141
+ },
142
+ {
143
+ type: 'metric',
144
+ buffered: true,
145
+ }
146
+ );
147
+ };
148
+ const disable = (): void => {
149
+ observers.forEach((observer) => {
150
+ observer.disconnect();
151
+ });
152
+ performance.clearMarks();
153
+ performance.clearMeasures();
154
+ performance.clearMetrics();
155
+ observers = [];
156
+ isObserving = false;
157
+ sessionStartedAt = 0;
158
+ origin = 0;
159
+ };
160
+ const isEnabled = (): boolean => isObserving;
161
+ const dispose = (): void => {
162
+ disable();
163
+ };
164
+
165
+ return {
166
+ enable,
167
+ disable,
168
+ isEnabled,
169
+ dispose,
170
+ };
171
+ };
@@ -0,0 +1,31 @@
1
+ import { useRozeniteDevToolsClient } from '@rozenite/plugin-bridge';
2
+ import { useEffect } from 'react';
3
+ import { getPerformanceMonitor } from './performance-monitor';
4
+ import { PerformanceMonitorEventMap } from '../shared/types';
5
+
6
+ export const usePerformanceMonitorDevTools = () => {
7
+ const client = useRozeniteDevToolsClient<PerformanceMonitorEventMap>({
8
+ pluginId: '@rozenite/performance-monitor-plugin',
9
+ });
10
+
11
+ useEffect(() => {
12
+ if (!client) {
13
+ return;
14
+ }
15
+
16
+ const performanceMonitor = getPerformanceMonitor(client);
17
+
18
+ const subscription = client.onMessage('setEnabled', ({ enabled }) => {
19
+ if (enabled) {
20
+ performanceMonitor.enable();
21
+ } else {
22
+ performanceMonitor.disable();
23
+ }
24
+ });
25
+
26
+ return () => {
27
+ subscription.remove();
28
+ performanceMonitor.dispose();
29
+ };
30
+ }, [client]);
31
+ };