@flotrace/runtime 2.2.4 → 2.3.1
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.
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +104 -38
- package/dist/index.mjs +117 -40
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -81,7 +81,7 @@ interface FloTraceProviderProps {
|
|
|
81
81
|
* );
|
|
82
82
|
* ```
|
|
83
83
|
*/
|
|
84
|
-
declare function FloTraceProvider({ children, config, stores, reduxStore, queryClient }: FloTraceProviderProps): JSX.Element;
|
|
84
|
+
declare function FloTraceProvider({ children, config, stores, reduxStore, queryClient, }: FloTraceProviderProps): JSX.Element;
|
|
85
85
|
/**
|
|
86
86
|
* Higher-order component to wrap a component with FloTrace profiling.
|
|
87
87
|
* Use this for targeted profiling of specific components.
|
package/dist/index.d.ts
CHANGED
|
@@ -81,7 +81,7 @@ interface FloTraceProviderProps {
|
|
|
81
81
|
* );
|
|
82
82
|
* ```
|
|
83
83
|
*/
|
|
84
|
-
declare function FloTraceProvider({ children, config, stores, reduxStore, queryClient }: FloTraceProviderProps): JSX.Element;
|
|
84
|
+
declare function FloTraceProvider({ children, config, stores, reduxStore, queryClient, }: FloTraceProviderProps): JSX.Element;
|
|
85
85
|
/**
|
|
86
86
|
* Higher-order component to wrap a component with FloTrace profiling.
|
|
87
87
|
* Use this for targeted profiling of specific components.
|
package/dist/index.js
CHANGED
|
@@ -50,7 +50,7 @@ var import_runtime_core3 = require("@flotrace/runtime-core");
|
|
|
50
50
|
// package.json
|
|
51
51
|
var package_default = {
|
|
52
52
|
name: "@flotrace/runtime",
|
|
53
|
-
version: "2.
|
|
53
|
+
version: "2.3.1",
|
|
54
54
|
description: "Runtime package for FloTrace - enables real-time render tracking in your React app",
|
|
55
55
|
main: "./dist/index.js",
|
|
56
56
|
module: "./dist/index.mjs",
|
|
@@ -78,7 +78,7 @@ var package_default = {
|
|
|
78
78
|
"release:major": "npm version major && npm publish"
|
|
79
79
|
},
|
|
80
80
|
dependencies: {
|
|
81
|
-
"@flotrace/runtime-core": "2.
|
|
81
|
+
"@flotrace/runtime-core": "2.3.1"
|
|
82
82
|
},
|
|
83
83
|
peerDependencies: {
|
|
84
84
|
react: ">=16.9.0",
|
|
@@ -390,11 +390,15 @@ function patchFetch() {
|
|
|
390
390
|
const entry = createEntry(method, parsedUrl, init);
|
|
391
391
|
const startTime = performance.now();
|
|
392
392
|
if (init?.signal) {
|
|
393
|
-
init.signal.addEventListener(
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
393
|
+
init.signal.addEventListener(
|
|
394
|
+
"abort",
|
|
395
|
+
() => {
|
|
396
|
+
entry.state = "aborted";
|
|
397
|
+
entry.durationMs = performance.now() - startTime;
|
|
398
|
+
pushEntry(entry);
|
|
399
|
+
},
|
|
400
|
+
{ once: true }
|
|
401
|
+
);
|
|
398
402
|
}
|
|
399
403
|
pushEntry({ ...entry });
|
|
400
404
|
try {
|
|
@@ -571,10 +575,7 @@ function parseUrl(url) {
|
|
|
571
575
|
return { path: url.split("?")[0] ?? url, host: "" };
|
|
572
576
|
}
|
|
573
577
|
}
|
|
574
|
-
var COMBINED_NOISE_PATTERN = new RegExp(
|
|
575
|
-
NOISE_URL_PATTERNS.map((r) => r.source).join("|"),
|
|
576
|
-
"i"
|
|
577
|
-
);
|
|
578
|
+
var COMBINED_NOISE_PATTERN = new RegExp(NOISE_URL_PATTERNS.map((r) => r.source).join("|"), "i");
|
|
578
579
|
function isNoiseUrl(url) {
|
|
579
580
|
return COMBINED_NOISE_PATTERN.test(url);
|
|
580
581
|
}
|
|
@@ -592,7 +593,8 @@ function parseXhrContentLength(xhr) {
|
|
|
592
593
|
function hasHeader(init, name) {
|
|
593
594
|
if (!init?.headers) return false;
|
|
594
595
|
if (init.headers instanceof Headers) return init.headers.has(name);
|
|
595
|
-
if (Array.isArray(init.headers))
|
|
596
|
+
if (Array.isArray(init.headers))
|
|
597
|
+
return init.headers.some(([k]) => k.toLowerCase() === name.toLowerCase());
|
|
596
598
|
if (typeof init.headers === "object") {
|
|
597
599
|
return Object.keys(init.headers).some((k) => k.toLowerCase() === name.toLowerCase());
|
|
598
600
|
}
|
|
@@ -675,7 +677,13 @@ var FloTraceContext = (0, import_react.createContext)(null);
|
|
|
675
677
|
function useFloTrace() {
|
|
676
678
|
return (0, import_react.useContext)(FloTraceContext);
|
|
677
679
|
}
|
|
678
|
-
function FloTraceProvider({
|
|
680
|
+
function FloTraceProvider({
|
|
681
|
+
children,
|
|
682
|
+
config = {},
|
|
683
|
+
stores,
|
|
684
|
+
reduxStore,
|
|
685
|
+
queryClient
|
|
686
|
+
}) {
|
|
679
687
|
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
680
688
|
console.warn(
|
|
681
689
|
"[FloTrace] FloTraceProvider (from @flotrace/runtime) detected a React Native environment. Install @flotrace/runtime-native and use FloTraceProviderNative instead. Skipping attach."
|
|
@@ -741,13 +749,22 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
|
|
|
741
749
|
case "ext:startTracking":
|
|
742
750
|
trackingOptionsRef.current = message.options || {};
|
|
743
751
|
if (message.options?.trackZustand && storesRef.current && Object.keys(storesRef.current).length > 0) {
|
|
744
|
-
safeTrackerOp(
|
|
752
|
+
safeTrackerOp(
|
|
753
|
+
"Zustand install",
|
|
754
|
+
() => (0, import_runtime_core3.installZustandTracker)(storesRef.current, client3)
|
|
755
|
+
);
|
|
745
756
|
}
|
|
746
757
|
if (message.options?.trackRedux && reduxStoreRef.current) {
|
|
747
|
-
safeTrackerOp(
|
|
758
|
+
safeTrackerOp(
|
|
759
|
+
"Redux install",
|
|
760
|
+
() => (0, import_runtime_core3.installReduxTracker)(reduxStoreRef.current, client3)
|
|
761
|
+
);
|
|
748
762
|
}
|
|
749
763
|
if (message.options?.trackTanstackQuery && queryClientRef.current) {
|
|
750
|
-
safeTrackerOp(
|
|
764
|
+
safeTrackerOp(
|
|
765
|
+
"TanStack Query install",
|
|
766
|
+
() => (0, import_runtime_core3.installTanStackQueryTracker)(queryClientRef.current, client3)
|
|
767
|
+
);
|
|
751
768
|
}
|
|
752
769
|
if (message.options?.trackRouter) {
|
|
753
770
|
safeTrackerOp("Router install", () => installRouterTracker(client3));
|
|
@@ -873,7 +890,11 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
|
|
|
873
890
|
break;
|
|
874
891
|
// --- Individual tracker start/stop (sidebar panel show/hide) ---
|
|
875
892
|
case "ext:startReduxTracking":
|
|
876
|
-
if (reduxStoreRef.current)
|
|
893
|
+
if (reduxStoreRef.current)
|
|
894
|
+
safeTrackerOp(
|
|
895
|
+
"Redux install",
|
|
896
|
+
() => (0, import_runtime_core3.installReduxTracker)(reduxStoreRef.current, client3)
|
|
897
|
+
);
|
|
877
898
|
break;
|
|
878
899
|
case "ext:stopReduxTracking":
|
|
879
900
|
safeTrackerOp("Redux uninstall", import_runtime_core3.uninstallReduxTracker);
|
|
@@ -886,14 +907,21 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
|
|
|
886
907
|
break;
|
|
887
908
|
case "ext:startZustandTracking":
|
|
888
909
|
if (storesRef.current && Object.keys(storesRef.current).length > 0) {
|
|
889
|
-
safeTrackerOp(
|
|
910
|
+
safeTrackerOp(
|
|
911
|
+
"Zustand install",
|
|
912
|
+
() => (0, import_runtime_core3.installZustandTracker)(storesRef.current, client3)
|
|
913
|
+
);
|
|
890
914
|
}
|
|
891
915
|
break;
|
|
892
916
|
case "ext:stopZustandTracking":
|
|
893
917
|
safeTrackerOp("Zustand uninstall", import_runtime_core3.uninstallZustandTracker);
|
|
894
918
|
break;
|
|
895
919
|
case "ext:startTanstackTracking":
|
|
896
|
-
if (queryClientRef.current)
|
|
920
|
+
if (queryClientRef.current)
|
|
921
|
+
safeTrackerOp(
|
|
922
|
+
"TanStack Query install",
|
|
923
|
+
() => (0, import_runtime_core3.installTanStackQueryTracker)(queryClientRef.current, client3)
|
|
924
|
+
);
|
|
897
925
|
break;
|
|
898
926
|
case "ext:stopTanstackTracking":
|
|
899
927
|
safeTrackerOp("TanStack Query uninstall", import_runtime_core3.uninstallTanStackQueryTracker);
|
|
@@ -906,9 +934,43 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
|
|
|
906
934
|
}
|
|
907
935
|
});
|
|
908
936
|
client3.connect();
|
|
937
|
+
(0, import_runtime_core3.setDuplicateKeyEmitter)((evt) => {
|
|
938
|
+
try {
|
|
939
|
+
if (!client3.connected) return;
|
|
940
|
+
client3.send({
|
|
941
|
+
type: "runtime:duplicateKey",
|
|
942
|
+
callSiteId: evt.callSiteId,
|
|
943
|
+
fileName: evt.fileName,
|
|
944
|
+
lineNumber: evt.lineNumber,
|
|
945
|
+
columnNumber: evt.columnNumber,
|
|
946
|
+
duplicateKey: evt.duplicateKey,
|
|
947
|
+
occurrences: evt.occurrences,
|
|
948
|
+
timestamp: Date.now()
|
|
949
|
+
});
|
|
950
|
+
} catch (error) {
|
|
951
|
+
console.error("[FloTrace] Error emitting runtime:duplicateKey:", error);
|
|
952
|
+
}
|
|
953
|
+
});
|
|
954
|
+
const callSiteMetricsTimer = setInterval(() => {
|
|
955
|
+
try {
|
|
956
|
+
if (!client3.connected) return;
|
|
957
|
+
if (!(0, import_runtime_core3.isJsxRuntimeActive)()) return;
|
|
958
|
+
const metrics = (0, import_runtime_core3.computeCallSiteMetricsPayload)();
|
|
959
|
+
if (metrics === null) return;
|
|
960
|
+
client3.send({
|
|
961
|
+
type: "runtime:callSiteMetrics",
|
|
962
|
+
metrics,
|
|
963
|
+
timestamp: Date.now()
|
|
964
|
+
});
|
|
965
|
+
} catch (error) {
|
|
966
|
+
console.error("[FloTrace] Error emitting runtime:callSiteMetrics:", error);
|
|
967
|
+
}
|
|
968
|
+
}, 1e3);
|
|
909
969
|
return () => {
|
|
910
970
|
unsubConnection();
|
|
911
971
|
unsubMessage();
|
|
972
|
+
(0, import_runtime_core3.setDuplicateKeyEmitter)(null);
|
|
973
|
+
clearInterval(callSiteMetricsTimer);
|
|
912
974
|
pendingCleanupTimer = setTimeout(() => {
|
|
913
975
|
pendingCleanupTimer = null;
|
|
914
976
|
safeTrackerOp("cleanup fiberTreeWalker", import_runtime_core3.uninstallFiberTreeWalker);
|
|
@@ -919,28 +981,32 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
|
|
|
919
981
|
safeTrackerOp("cleanup timelineTracker", import_runtime_core3.uninstallTimelineTracker);
|
|
920
982
|
safeTrackerOp("cleanup networkTracker", uninstallNetworkTracker);
|
|
921
983
|
safeTrackerOp("cleanup websocketClient", import_runtime_core3.disposeWebSocketClient);
|
|
984
|
+
safeTrackerOp("cleanup callSiteRenders", import_runtime_core3.clearCallSiteRenders);
|
|
922
985
|
}, 100);
|
|
923
986
|
};
|
|
924
987
|
}, [mergedConfig.enabled, mergedConfig.port, mergedConfig.appName]);
|
|
925
|
-
const onRenderCallback = (0, import_react.useCallback)(
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
988
|
+
const onRenderCallback = (0, import_react.useCallback)(
|
|
989
|
+
(id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
|
|
990
|
+
try {
|
|
991
|
+
if (!enabledRef.current) return;
|
|
992
|
+
const client3 = (0, import_runtime_core3.getWebSocketClient)();
|
|
993
|
+
if (!client3.connected) return;
|
|
994
|
+
const normalizedPhase = phase === "nested-update" ? "update" : phase;
|
|
995
|
+
client3.send({
|
|
996
|
+
type: "runtime:render",
|
|
997
|
+
componentName: id,
|
|
998
|
+
phase: normalizedPhase,
|
|
999
|
+
actualDuration,
|
|
1000
|
+
baseDuration,
|
|
1001
|
+
timestamp: commitTime
|
|
1002
|
+
});
|
|
1003
|
+
(0, import_runtime_core3.requestTreeSnapshot)();
|
|
1004
|
+
} catch (error) {
|
|
1005
|
+
console.error("[FloTrace] Error in Profiler callback:", error);
|
|
1006
|
+
}
|
|
1007
|
+
},
|
|
1008
|
+
[]
|
|
1009
|
+
);
|
|
944
1010
|
const contextValue = {
|
|
945
1011
|
connected,
|
|
946
1012
|
enabled: mergedConfig.enabled,
|
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,14 @@
|
|
|
2
2
|
export * from "@flotrace/runtime-core";
|
|
3
3
|
|
|
4
4
|
// src/FloTraceProvider.tsx
|
|
5
|
-
import React, {
|
|
5
|
+
import React, {
|
|
6
|
+
useCallback,
|
|
7
|
+
useEffect,
|
|
8
|
+
useRef,
|
|
9
|
+
createContext,
|
|
10
|
+
useContext,
|
|
11
|
+
Profiler
|
|
12
|
+
} from "react";
|
|
6
13
|
import {
|
|
7
14
|
DEFAULT_CONFIG,
|
|
8
15
|
getWebSocketClient,
|
|
@@ -27,13 +34,17 @@ import {
|
|
|
27
34
|
uninstallTimelineTracker,
|
|
28
35
|
getTimeline,
|
|
29
36
|
detectWebFramework,
|
|
30
|
-
resolveValueTrace
|
|
37
|
+
resolveValueTrace,
|
|
38
|
+
computeCallSiteMetricsPayload,
|
|
39
|
+
setDuplicateKeyEmitter,
|
|
40
|
+
isJsxRuntimeActive,
|
|
41
|
+
clearCallSiteRenders
|
|
31
42
|
} from "@flotrace/runtime-core";
|
|
32
43
|
|
|
33
44
|
// package.json
|
|
34
45
|
var package_default = {
|
|
35
46
|
name: "@flotrace/runtime",
|
|
36
|
-
version: "2.
|
|
47
|
+
version: "2.3.1",
|
|
37
48
|
description: "Runtime package for FloTrace - enables real-time render tracking in your React app",
|
|
38
49
|
main: "./dist/index.js",
|
|
39
50
|
module: "./dist/index.mjs",
|
|
@@ -61,7 +72,7 @@ var package_default = {
|
|
|
61
72
|
"release:major": "npm version major && npm publish"
|
|
62
73
|
},
|
|
63
74
|
dependencies: {
|
|
64
|
-
"@flotrace/runtime-core": "2.
|
|
75
|
+
"@flotrace/runtime-core": "2.3.1"
|
|
65
76
|
},
|
|
66
77
|
peerDependencies: {
|
|
67
78
|
react: ">=16.9.0",
|
|
@@ -379,11 +390,15 @@ function patchFetch() {
|
|
|
379
390
|
const entry = createEntry(method, parsedUrl, init);
|
|
380
391
|
const startTime = performance.now();
|
|
381
392
|
if (init?.signal) {
|
|
382
|
-
init.signal.addEventListener(
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
393
|
+
init.signal.addEventListener(
|
|
394
|
+
"abort",
|
|
395
|
+
() => {
|
|
396
|
+
entry.state = "aborted";
|
|
397
|
+
entry.durationMs = performance.now() - startTime;
|
|
398
|
+
pushEntry(entry);
|
|
399
|
+
},
|
|
400
|
+
{ once: true }
|
|
401
|
+
);
|
|
387
402
|
}
|
|
388
403
|
pushEntry({ ...entry });
|
|
389
404
|
try {
|
|
@@ -560,10 +575,7 @@ function parseUrl(url) {
|
|
|
560
575
|
return { path: url.split("?")[0] ?? url, host: "" };
|
|
561
576
|
}
|
|
562
577
|
}
|
|
563
|
-
var COMBINED_NOISE_PATTERN = new RegExp(
|
|
564
|
-
NOISE_URL_PATTERNS.map((r) => r.source).join("|"),
|
|
565
|
-
"i"
|
|
566
|
-
);
|
|
578
|
+
var COMBINED_NOISE_PATTERN = new RegExp(NOISE_URL_PATTERNS.map((r) => r.source).join("|"), "i");
|
|
567
579
|
function isNoiseUrl(url) {
|
|
568
580
|
return COMBINED_NOISE_PATTERN.test(url);
|
|
569
581
|
}
|
|
@@ -581,7 +593,8 @@ function parseXhrContentLength(xhr) {
|
|
|
581
593
|
function hasHeader(init, name) {
|
|
582
594
|
if (!init?.headers) return false;
|
|
583
595
|
if (init.headers instanceof Headers) return init.headers.has(name);
|
|
584
|
-
if (Array.isArray(init.headers))
|
|
596
|
+
if (Array.isArray(init.headers))
|
|
597
|
+
return init.headers.some(([k]) => k.toLowerCase() === name.toLowerCase());
|
|
585
598
|
if (typeof init.headers === "object") {
|
|
586
599
|
return Object.keys(init.headers).some((k) => k.toLowerCase() === name.toLowerCase());
|
|
587
600
|
}
|
|
@@ -664,7 +677,13 @@ var FloTraceContext = createContext(null);
|
|
|
664
677
|
function useFloTrace() {
|
|
665
678
|
return useContext(FloTraceContext);
|
|
666
679
|
}
|
|
667
|
-
function FloTraceProvider({
|
|
680
|
+
function FloTraceProvider({
|
|
681
|
+
children,
|
|
682
|
+
config = {},
|
|
683
|
+
stores,
|
|
684
|
+
reduxStore,
|
|
685
|
+
queryClient
|
|
686
|
+
}) {
|
|
668
687
|
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
669
688
|
console.warn(
|
|
670
689
|
"[FloTrace] FloTraceProvider (from @flotrace/runtime) detected a React Native environment. Install @flotrace/runtime-native and use FloTraceProviderNative instead. Skipping attach."
|
|
@@ -730,13 +749,22 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
|
|
|
730
749
|
case "ext:startTracking":
|
|
731
750
|
trackingOptionsRef.current = message.options || {};
|
|
732
751
|
if (message.options?.trackZustand && storesRef.current && Object.keys(storesRef.current).length > 0) {
|
|
733
|
-
safeTrackerOp(
|
|
752
|
+
safeTrackerOp(
|
|
753
|
+
"Zustand install",
|
|
754
|
+
() => installZustandTracker(storesRef.current, client3)
|
|
755
|
+
);
|
|
734
756
|
}
|
|
735
757
|
if (message.options?.trackRedux && reduxStoreRef.current) {
|
|
736
|
-
safeTrackerOp(
|
|
758
|
+
safeTrackerOp(
|
|
759
|
+
"Redux install",
|
|
760
|
+
() => installReduxTracker(reduxStoreRef.current, client3)
|
|
761
|
+
);
|
|
737
762
|
}
|
|
738
763
|
if (message.options?.trackTanstackQuery && queryClientRef.current) {
|
|
739
|
-
safeTrackerOp(
|
|
764
|
+
safeTrackerOp(
|
|
765
|
+
"TanStack Query install",
|
|
766
|
+
() => installTanStackQueryTracker(queryClientRef.current, client3)
|
|
767
|
+
);
|
|
740
768
|
}
|
|
741
769
|
if (message.options?.trackRouter) {
|
|
742
770
|
safeTrackerOp("Router install", () => installRouterTracker(client3));
|
|
@@ -862,7 +890,11 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
|
|
|
862
890
|
break;
|
|
863
891
|
// --- Individual tracker start/stop (sidebar panel show/hide) ---
|
|
864
892
|
case "ext:startReduxTracking":
|
|
865
|
-
if (reduxStoreRef.current)
|
|
893
|
+
if (reduxStoreRef.current)
|
|
894
|
+
safeTrackerOp(
|
|
895
|
+
"Redux install",
|
|
896
|
+
() => installReduxTracker(reduxStoreRef.current, client3)
|
|
897
|
+
);
|
|
866
898
|
break;
|
|
867
899
|
case "ext:stopReduxTracking":
|
|
868
900
|
safeTrackerOp("Redux uninstall", uninstallReduxTracker);
|
|
@@ -875,14 +907,21 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
|
|
|
875
907
|
break;
|
|
876
908
|
case "ext:startZustandTracking":
|
|
877
909
|
if (storesRef.current && Object.keys(storesRef.current).length > 0) {
|
|
878
|
-
safeTrackerOp(
|
|
910
|
+
safeTrackerOp(
|
|
911
|
+
"Zustand install",
|
|
912
|
+
() => installZustandTracker(storesRef.current, client3)
|
|
913
|
+
);
|
|
879
914
|
}
|
|
880
915
|
break;
|
|
881
916
|
case "ext:stopZustandTracking":
|
|
882
917
|
safeTrackerOp("Zustand uninstall", uninstallZustandTracker);
|
|
883
918
|
break;
|
|
884
919
|
case "ext:startTanstackTracking":
|
|
885
|
-
if (queryClientRef.current)
|
|
920
|
+
if (queryClientRef.current)
|
|
921
|
+
safeTrackerOp(
|
|
922
|
+
"TanStack Query install",
|
|
923
|
+
() => installTanStackQueryTracker(queryClientRef.current, client3)
|
|
924
|
+
);
|
|
886
925
|
break;
|
|
887
926
|
case "ext:stopTanstackTracking":
|
|
888
927
|
safeTrackerOp("TanStack Query uninstall", uninstallTanStackQueryTracker);
|
|
@@ -895,9 +934,43 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
|
|
|
895
934
|
}
|
|
896
935
|
});
|
|
897
936
|
client3.connect();
|
|
937
|
+
setDuplicateKeyEmitter((evt) => {
|
|
938
|
+
try {
|
|
939
|
+
if (!client3.connected) return;
|
|
940
|
+
client3.send({
|
|
941
|
+
type: "runtime:duplicateKey",
|
|
942
|
+
callSiteId: evt.callSiteId,
|
|
943
|
+
fileName: evt.fileName,
|
|
944
|
+
lineNumber: evt.lineNumber,
|
|
945
|
+
columnNumber: evt.columnNumber,
|
|
946
|
+
duplicateKey: evt.duplicateKey,
|
|
947
|
+
occurrences: evt.occurrences,
|
|
948
|
+
timestamp: Date.now()
|
|
949
|
+
});
|
|
950
|
+
} catch (error) {
|
|
951
|
+
console.error("[FloTrace] Error emitting runtime:duplicateKey:", error);
|
|
952
|
+
}
|
|
953
|
+
});
|
|
954
|
+
const callSiteMetricsTimer = setInterval(() => {
|
|
955
|
+
try {
|
|
956
|
+
if (!client3.connected) return;
|
|
957
|
+
if (!isJsxRuntimeActive()) return;
|
|
958
|
+
const metrics = computeCallSiteMetricsPayload();
|
|
959
|
+
if (metrics === null) return;
|
|
960
|
+
client3.send({
|
|
961
|
+
type: "runtime:callSiteMetrics",
|
|
962
|
+
metrics,
|
|
963
|
+
timestamp: Date.now()
|
|
964
|
+
});
|
|
965
|
+
} catch (error) {
|
|
966
|
+
console.error("[FloTrace] Error emitting runtime:callSiteMetrics:", error);
|
|
967
|
+
}
|
|
968
|
+
}, 1e3);
|
|
898
969
|
return () => {
|
|
899
970
|
unsubConnection();
|
|
900
971
|
unsubMessage();
|
|
972
|
+
setDuplicateKeyEmitter(null);
|
|
973
|
+
clearInterval(callSiteMetricsTimer);
|
|
901
974
|
pendingCleanupTimer = setTimeout(() => {
|
|
902
975
|
pendingCleanupTimer = null;
|
|
903
976
|
safeTrackerOp("cleanup fiberTreeWalker", uninstallFiberTreeWalker);
|
|
@@ -908,28 +981,32 @@ function FloTraceProvider({ children, config = {}, stores, reduxStore, queryClie
|
|
|
908
981
|
safeTrackerOp("cleanup timelineTracker", uninstallTimelineTracker);
|
|
909
982
|
safeTrackerOp("cleanup networkTracker", uninstallNetworkTracker);
|
|
910
983
|
safeTrackerOp("cleanup websocketClient", disposeWebSocketClient);
|
|
984
|
+
safeTrackerOp("cleanup callSiteRenders", clearCallSiteRenders);
|
|
911
985
|
}, 100);
|
|
912
986
|
};
|
|
913
987
|
}, [mergedConfig.enabled, mergedConfig.port, mergedConfig.appName]);
|
|
914
|
-
const onRenderCallback = useCallback(
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
988
|
+
const onRenderCallback = useCallback(
|
|
989
|
+
(id, phase, actualDuration, baseDuration, _startTime, commitTime) => {
|
|
990
|
+
try {
|
|
991
|
+
if (!enabledRef.current) return;
|
|
992
|
+
const client3 = getWebSocketClient();
|
|
993
|
+
if (!client3.connected) return;
|
|
994
|
+
const normalizedPhase = phase === "nested-update" ? "update" : phase;
|
|
995
|
+
client3.send({
|
|
996
|
+
type: "runtime:render",
|
|
997
|
+
componentName: id,
|
|
998
|
+
phase: normalizedPhase,
|
|
999
|
+
actualDuration,
|
|
1000
|
+
baseDuration,
|
|
1001
|
+
timestamp: commitTime
|
|
1002
|
+
});
|
|
1003
|
+
requestTreeSnapshot();
|
|
1004
|
+
} catch (error) {
|
|
1005
|
+
console.error("[FloTrace] Error in Profiler callback:", error);
|
|
1006
|
+
}
|
|
1007
|
+
},
|
|
1008
|
+
[]
|
|
1009
|
+
);
|
|
933
1010
|
const contextValue = {
|
|
934
1011
|
connected,
|
|
935
1012
|
enabled: mergedConfig.enabled,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flotrace/runtime",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "Runtime package for FloTrace - enables real-time render tracking in your React app",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"release:major": "npm version major && npm publish"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@flotrace/runtime-core": "2.
|
|
31
|
+
"@flotrace/runtime-core": "2.3.1"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"react": ">=16.9.0",
|