react-perf-x 0.1.0

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 (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +170 -0
  3. package/dist/components/PerformanceProfiler.d.ts +13 -0
  4. package/dist/components/PerformanceProfiler.d.ts.map +1 -0
  5. package/dist/components/index.d.ts +2 -0
  6. package/dist/components/index.d.ts.map +1 -0
  7. package/dist/hoc/index.d.ts +2 -0
  8. package/dist/hoc/index.d.ts.map +1 -0
  9. package/dist/hoc/withSmartMemo.d.ts +12 -0
  10. package/dist/hoc/withSmartMemo.d.ts.map +1 -0
  11. package/dist/hooks/index.d.ts +10 -0
  12. package/dist/hooks/index.d.ts.map +1 -0
  13. package/dist/hooks/useDebounce.d.ts +2 -0
  14. package/dist/hooks/useDebounce.d.ts.map +1 -0
  15. package/dist/hooks/useDeepCompareEffect.d.ts +12 -0
  16. package/dist/hooks/useDeepCompareEffect.d.ts.map +1 -0
  17. package/dist/hooks/useDeepCompareMemo.d.ts +12 -0
  18. package/dist/hooks/useDeepCompareMemo.d.ts.map +1 -0
  19. package/dist/hooks/useLazyRef.d.ts +11 -0
  20. package/dist/hooks/useLazyRef.d.ts.map +1 -0
  21. package/dist/hooks/usePrevious.d.ts +9 -0
  22. package/dist/hooks/usePrevious.d.ts.map +1 -0
  23. package/dist/hooks/useRenderCount.d.ts +11 -0
  24. package/dist/hooks/useRenderCount.d.ts.map +1 -0
  25. package/dist/hooks/useRenderTracker.d.ts +10 -0
  26. package/dist/hooks/useRenderTracker.d.ts.map +1 -0
  27. package/dist/hooks/useThrottle.d.ts +7 -0
  28. package/dist/hooks/useThrottle.d.ts.map +1 -0
  29. package/dist/hooks/useWhyDidYouRender.d.ts +13 -0
  30. package/dist/hooks/useWhyDidYouRender.d.ts.map +1 -0
  31. package/dist/index.cjs.js +2 -0
  32. package/dist/index.cjs.js.map +1 -0
  33. package/dist/index.d.ts +11 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +2 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/types.d.ts +25 -0
  38. package/dist/types.d.ts.map +1 -0
  39. package/dist/utils/deepCompare.d.ts +6 -0
  40. package/dist/utils/deepCompare.d.ts.map +1 -0
  41. package/dist/utils/index.d.ts +3 -0
  42. package/dist/utils/index.d.ts.map +1 -0
  43. package/dist/utils/isDev.d.ts +2 -0
  44. package/dist/utils/isDev.d.ts.map +1 -0
  45. package/package.json +62 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ReactPerfX Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,170 @@
1
+ # ReactPerfX ⚡
2
+
3
+ > Lightweight, tree-shakable React performance optimization library — zero external dependencies, TypeScript-first.
4
+
5
+ [![CI](https://github.com/sujalsarnobat/ReactPerfX/actions/workflows/ci.yml/badge.svg)](https://github.com/sujalsarnobat/ReactPerfX/actions)
6
+ [![npm](https://img.shields.io/npm/v/react-perf-x)](https://www.npmjs.com/package/react-perf-x)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
8
+ [![Bundle Size](https://img.shields.io/bundlephobia/minzip/react-perf-x)](https://bundlephobia.com/result?p=react-perf-x)
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm install react-perf-x
14
+ ```
15
+
16
+ ## Features
17
+
18
+ | Feature | Import | Description |
19
+ |---------|--------|-------------|
20
+ | `useRenderTracker` | Hook | Log render counts with optional warning threshold |
21
+ | `useWhyDidYouRender` | Hook | Log exactly which props/state changed on re-render |
22
+ | `useDeepCompareEffect` | Hook | `useEffect` with deep dependency comparison |
23
+ | `useDeepCompareMemo` | Hook | `useMemo` with deep dependency comparison |
24
+ | `useDebounce` | Hook | Debounce any value |
25
+ | `useThrottle` | Hook | Throttle any value |
26
+ | `usePrevious` | Hook | Track previous value of any state/prop |
27
+ | `useRenderCount` | Hook | Get current render count as a number |
28
+ | `useLazyRef` | Hook | Lazy initialization for expensive refs |
29
+ | `withSmartMemo` | HOC | Deep-comparison memoization with custom comparator |
30
+ | `PerformanceProfiler` | Component | Measure component render duration |
31
+ | `deepCompare` | Utility | Deep equality comparison |
32
+ | `isDev` | Utility | Check if running in development mode |
33
+
34
+ ## Quick Start
35
+
36
+ ### Track Re-renders
37
+ ```tsx
38
+ import { useRenderTracker } from "react-perf-x";
39
+
40
+ function Dashboard() {
41
+ useRenderTracker("Dashboard", { warnAfter: 10 });
42
+ return <div>...</div>;
43
+ }
44
+ ```
45
+
46
+ ### Debug Why Components Re-render
47
+ ```tsx
48
+ import { useWhyDidYouRender } from "react-perf-x";
49
+
50
+ function UserCard({ name, age, filters }) {
51
+ useWhyDidYouRender("UserCard", { name, age, filters });
52
+ // Console: [UserCard] Re-rendered because:
53
+ // filters changed:
54
+ // prev: {status: "active"}
55
+ // next: {status: "inactive"}
56
+ return <div>{name}</div>;
57
+ }
58
+ ```
59
+
60
+ ### Deep Compare Effect
61
+ ```tsx
62
+ import { useDeepCompareEffect } from "react-perf-x";
63
+
64
+ function DataList({ filters }) {
65
+ useDeepCompareEffect(() => {
66
+ fetchData(filters); // Only re-fetches when filters *deeply* change
67
+ }, [filters]);
68
+ return <div>...</div>;
69
+ }
70
+ ```
71
+
72
+ ### Debounce & Throttle
73
+ ```tsx
74
+ import { useDebounce, useThrottle } from "react-perf-x";
75
+
76
+ function SearchBox({ query }) {
77
+ const debouncedQuery = useDebounce(query, 300);
78
+ const throttledScroll = useThrottle(scrollPosition, 100);
79
+ }
80
+ ```
81
+
82
+ ### Smart Memoization
83
+ ```tsx
84
+ import { withSmartMemo } from "react-perf-x";
85
+
86
+ const MemoizedCard = withSmartMemo(UserCard);
87
+ // Uses deep comparison — won't re-render if props are deeply equal
88
+
89
+ // With custom comparator:
90
+ const CustomMemo = withSmartMemo(UserCard, (prev, next) => prev.id === next.id);
91
+ ```
92
+
93
+ ### Performance Profiling
94
+ ```tsx
95
+ import { PerformanceProfiler } from "react-perf-x";
96
+
97
+ function App() {
98
+ return (
99
+ <PerformanceProfiler
100
+ id="Dashboard"
101
+ onProfile={({ id, duration }) => console.log(`${id}: ${duration}ms`)}
102
+ >
103
+ <Dashboard />
104
+ </PerformanceProfiler>
105
+ );
106
+ }
107
+ ```
108
+
109
+ ## API Reference
110
+
111
+ ### Hooks
112
+
113
+ #### `useRenderTracker(componentName, options?)`
114
+ - `componentName: string` — Name shown in logs
115
+ - `options.warnAfter?: number` — Warn after this many renders
116
+
117
+ #### `useWhyDidYouRender(componentName, props)`
118
+ - `componentName: string` — Name shown in logs
119
+ - `props: Record<string, any>` — Object of values to track
120
+
121
+ #### `useDeepCompareEffect(effect, deps)`
122
+ - Same API as `useEffect`, but deep-compares dependencies
123
+
124
+ #### `useDeepCompareMemo(factory, deps)`
125
+ - Same API as `useMemo`, but deep-compares dependencies
126
+
127
+ #### `useDebounce<T>(value, delay): T`
128
+ - Returns debounced value after `delay` ms of inactivity
129
+
130
+ #### `useThrottle<T>(value, delay): T`
131
+ - Returns throttled value, updating at most once per `delay` ms
132
+
133
+ #### `usePrevious<T>(value): T | undefined`
134
+ - Returns value from the previous render
135
+
136
+ #### `useRenderCount(): number`
137
+ - Returns current render count
138
+
139
+ #### `useLazyRef<T>(initializer): MutableRefObject<T>`
140
+ - Lazily initializes ref value (initializer runs once)
141
+
142
+ ### HOC
143
+
144
+ #### `withSmartMemo<T>(Component, comparator?)`
145
+ - `comparator?: (prev, next) => boolean` — Custom comparator (defaults to `deepCompare`)
146
+
147
+ ### Components
148
+
149
+ #### `<PerformanceProfiler id? onProfile?>`
150
+ - `id?: string` — Identifier for the profiled component
151
+ - `onProfile?: (metrics: { id, duration }) => void` — Callback with render metrics
152
+
153
+ ## Requirements
154
+
155
+ - React 18+
156
+ - TypeScript 5+ (recommended)
157
+
158
+ ## Development
159
+
160
+ ```bash
161
+ npm install # Install dependencies
162
+ npm test # Run tests
163
+ npm run test:coverage # Run tests with coverage
164
+ npm run lint # Lint source files
165
+ npm run build # Build ESM + CJS bundles
166
+ ```
167
+
168
+ ## License
169
+
170
+ [MIT](LICENSE)
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ import type { PerformanceProfilerProps } from "../types";
3
+ /**
4
+ * Wraps children and measures render duration.
5
+ * Logs to console in development mode and calls onProfile callback with metrics.
6
+ *
7
+ * @example
8
+ * <PerformanceProfiler id="Dashboard" onProfile={({ id, duration }) => log(id, duration)}>
9
+ * <Dashboard />
10
+ * </PerformanceProfiler>
11
+ */
12
+ export declare const PerformanceProfiler: React.FC<PerformanceProfilerProps>;
13
+ //# sourceMappingURL=PerformanceProfiler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PerformanceProfiler.d.ts","sourceRoot":"","sources":["../../src/components/PerformanceProfiler.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAEjD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAEzD;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAkBlE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { PerformanceProfiler } from "./PerformanceProfiler";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { withSmartMemo } from "./withSmartMemo";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hoc/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import React from "react";
2
+ /**
3
+ * Wraps a component with optimized memoization using deep comparison.
4
+ * Supports custom comparator functions and preserves displayName.
5
+ *
6
+ * @example
7
+ * const MemoizedCard = withSmartMemo(UserCard);
8
+ * // Or with custom comparator:
9
+ * const MemoizedCard = withSmartMemo(UserCard, (prev, next) => prev.id === next.id);
10
+ */
11
+ export declare function withSmartMemo<T>(Component: React.ComponentType<T>, comparator?: (prev: T, next: T) => boolean): React.MemoExoticComponent<React.ComponentType<T>>;
12
+ //# sourceMappingURL=withSmartMemo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"withSmartMemo.d.ts","sourceRoot":"","sources":["../../src/hoc/withSmartMemo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,EACjC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,OAAO,qDAM3C"}
@@ -0,0 +1,10 @@
1
+ export { useRenderTracker } from "./useRenderTracker";
2
+ export { useDeepCompareEffect } from "./useDeepCompareEffect";
3
+ export { useDeepCompareMemo } from "./useDeepCompareMemo";
4
+ export { useDebounce } from "./useDebounce";
5
+ export { useThrottle } from "./useThrottle";
6
+ export { useWhyDidYouRender } from "./useWhyDidYouRender";
7
+ export { usePrevious } from "./usePrevious";
8
+ export { useRenderCount } from "./useRenderCount";
9
+ export { useLazyRef } from "./useLazyRef";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function useDebounce<T>(value: T, delay: number): T;
2
+ //# sourceMappingURL=useDebounce.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDebounce.d.ts","sourceRoot":"","sources":["../../src/hooks/useDebounce.ts"],"names":[],"mappings":"AAEA,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,CAOzD"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Like `useEffect`, but uses deep comparison on dependencies
3
+ * instead of reference equality. Avoids unnecessary effect runs
4
+ * when dependencies are deeply equal but have different references.
5
+ *
6
+ * @example
7
+ * useDeepCompareEffect(() => {
8
+ * fetchData(filters);
9
+ * }, [filters]);
10
+ */
11
+ export declare function useDeepCompareEffect(effect: () => void | (() => void), deps: any[]): void;
12
+ //# sourceMappingURL=useDeepCompareEffect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDeepCompareEffect.d.ts","sourceRoot":"","sources":["../../src/hooks/useDeepCompareEffect.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,EACjC,IAAI,EAAE,GAAG,EAAE,QAWZ"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Like `useMemo`, but uses deep comparison on dependencies
3
+ * instead of reference equality.
4
+ *
5
+ * @example
6
+ * const processed = useDeepCompareMemo(
7
+ * () => expensiveComputation(data),
8
+ * [data]
9
+ * );
10
+ */
11
+ export declare function useDeepCompareMemo<T>(factory: () => T, deps: any[]): T;
12
+ //# sourceMappingURL=useDeepCompareMemo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDeepCompareMemo.d.ts","sourceRoot":"","sources":["../../src/hooks/useDeepCompareMemo.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAChC,OAAO,EAAE,MAAM,CAAC,EAChB,IAAI,EAAE,GAAG,EAAE,GACZ,CAAC,CAUH"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Creates a ref with lazy initialization.
3
+ * The initializer function runs only once, on the first render.
4
+ * Useful for expensive initial values that React's `useRef` doesn't
5
+ * natively support lazy initialization for.
6
+ *
7
+ * @example
8
+ * const heavyData = useLazyRef(() => computeExpensiveValue());
9
+ */
10
+ export declare function useLazyRef<T>(initializer: () => T): React.MutableRefObject<T>;
11
+ //# sourceMappingURL=useLazyRef.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLazyRef.d.ts","sourceRoot":"","sources":["../../src/hooks/useLazyRef.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAU7E"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Returns the previous value of any state or prop.
3
+ * On the first render, returns `undefined`.
4
+ *
5
+ * @example
6
+ * const prevCount = usePrevious(count);
7
+ */
8
+ export declare function usePrevious<T>(value: T): T | undefined;
9
+ //# sourceMappingURL=usePrevious.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePrevious.d.ts","sourceRoot":"","sources":["../../src/hooks/usePrevious.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS,CAQtD"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Returns the current render count of the component as a number.
3
+ * Unlike `useRenderTracker`, this doesn't log — it just returns the count
4
+ * for use in conditional logic or testing.
5
+ *
6
+ * @example
7
+ * const count = useRenderCount();
8
+ * console.log(`This component has rendered ${count} times`);
9
+ */
10
+ export declare function useRenderCount(): number;
11
+ //# sourceMappingURL=useRenderCount.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRenderCount.d.ts","sourceRoot":"","sources":["../../src/hooks/useRenderCount.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAIvC"}
@@ -0,0 +1,10 @@
1
+ import type { UseRenderTrackerOptions } from "../types";
2
+ /**
3
+ * Tracks the number of renders for a component and logs to console in development mode.
4
+ * Optionally warns if the render count exceeds a threshold.
5
+ *
6
+ * @example
7
+ * useRenderTracker("DashboardCard", { warnAfter: 10 });
8
+ */
9
+ export declare function useRenderTracker(componentName: string, options?: UseRenderTrackerOptions): void;
10
+ //# sourceMappingURL=useRenderTracker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRenderTracker.d.ts","sourceRoot":"","sources":["../../src/hooks/useRenderTracker.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAExD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE,uBAA4B,QActC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Throttles a value, updating at most once per `delay` ms.
3
+ * Unlike the previous ref-based implementation, this uses useState
4
+ * so that value changes actually trigger re-renders.
5
+ */
6
+ export declare function useThrottle<T>(value: T, delay: number): T;
7
+ //# sourceMappingURL=useThrottle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useThrottle.d.ts","sourceRoot":"","sources":["../../src/hooks/useThrottle.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,CA4BzD"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Logs exactly which props/state values changed on re-render.
3
+ * Only logs in development mode.
4
+ *
5
+ * @example
6
+ * useWhyDidYouRender("MyComponent", { userId, filters, data });
7
+ * // Console: [MyComponent] Re-rendered because:
8
+ * // filters changed:
9
+ * // prev: {status: "active"}
10
+ * // next: {status: "inactive"}
11
+ */
12
+ export declare function useWhyDidYouRender(componentName: string, props: Record<string, any>): void;
13
+ //# sourceMappingURL=useWhyDidYouRender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useWhyDidYouRender.d.ts","sourceRoot":"","sources":["../../src/hooks/useWhyDidYouRender.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAC9B,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC3B,IAAI,CA4CN"}
@@ -0,0 +1,2 @@
1
+ "use strict";var e=require("react"),r=require("react/jsx-runtime");const t=()=>"development"===process.env.NODE_ENV;function n(e,r){return o(e,r,new WeakSet,new WeakSet)}function o(e,r,t,n){if(e===r)return!0;if("number"==typeof e&&"number"==typeof r&&isNaN(e)&&isNaN(r))return!0;if(null==e||null==r)return!1;if(typeof e!=typeof r)return!1;if("object"!=typeof e)return!1;if(e instanceof Date&&r instanceof Date)return e.getTime()===r.getTime();if(e instanceof Date!=r instanceof Date)return!1;if(e instanceof RegExp&&r instanceof RegExp)return e.source===r.source&&e.flags===r.flags;if(e instanceof RegExp!=r instanceof RegExp)return!1;if(e instanceof Map&&r instanceof Map){if(e.size!==r.size)return!1;for(const[u,s]of e)if(!r.has(u)||!o(s,r.get(u),t,n))return!1;return!0}if(e instanceof Map!=r instanceof Map)return!1;if(e instanceof Set&&r instanceof Set){if(e.size!==r.size)return!1;for(const t of e)if(!r.has(t))return!1;return!0}if(e instanceof Set!=r instanceof Set)return!1;if(t.has(e)&&n.has(r))return!0;if(t.has(e)||n.has(r))return!1;if(t.add(e),n.add(r),Array.isArray(e)&&Array.isArray(r)){if(e.length!==r.length)return!1;for(let u=0;u<e.length;u++)if(!o(e[u],r[u],t,n))return!1;return!0}if(Array.isArray(e)!==Array.isArray(r))return!1;const u=Object.keys(e),s=Object.keys(r);if(u.length!==s.length)return!1;for(const s of u)if(!Object.prototype.hasOwnProperty.call(r,s)||!o(e[s],r[s],t,n))return!1;return!0}exports.PerformanceProfiler=({children:n,id:o="Component",onProfile:u})=>{const s=e.useRef(performance.now());return e.useEffect(()=>{const e=performance.now()-s.current;t()&&console.log(`[${o}] Render duration: ${e.toFixed(2)}ms`),u?.({id:o,duration:e}),s.current=performance.now()}),r.jsx(r.Fragment,{children:n})},exports.deepCompare=n,exports.isDev=t,exports.useDebounce=function(r,t){const[n,o]=e.useState(r);return e.useEffect(()=>{const e=setTimeout(()=>o(r),t);return()=>clearTimeout(e)},[r,t]),n},exports.useDeepCompareEffect=function(r,t){const o=e.useRef(),u=e.useRef(0);n(o.current,t)||(o.current=t,u.current++),e.useEffect(r,[u.current])},exports.useDeepCompareMemo=function(r,t){const o=e.useRef(),u=e.useRef(0);return n(o.current,t)||(o.current=t,u.current++),e.useMemo(r,[u.current])},exports.useLazyRef=function(r){const t=e.useRef(null),n=e.useRef(!1);return n.current||(t.current=r(),n.current=!0),t},exports.usePrevious=function(r){const t=e.useRef();return e.useEffect(()=>{t.current=r}),t.current},exports.useRenderCount=function(){const r=e.useRef(0);return r.current++,r.current},exports.useRenderTracker=function(r,n={}){const o=e.useRef(0);e.useEffect(()=>{o.current++,t()&&(console.log(`[${r}] Render #${o.current}`),n.warnAfter&&o.current>n.warnAfter&&console.warn(`[${r}] Exceeded render threshold (${n.warnAfter})`))})},exports.useThrottle=function(r,t){const[n,o]=e.useState(r),u=e.useRef(Date.now()),s=e.useRef(null);return e.useEffect(()=>{const e=Date.now(),n=e-u.current;return n>=t?(o(r),u.current=e):(s.current&&clearTimeout(s.current),s.current=setTimeout(()=>{o(r),u.current=Date.now()},t-n)),()=>{s.current&&clearTimeout(s.current)}},[r,t]),n},exports.useWhyDidYouRender=function(r,o){const u=e.useRef();e.useEffect(()=>{if(t()){if(u.current){const e={},t=new Set([...Object.keys(u.current),...Object.keys(o)]);for(const r of t)n(u.current[r],o[r])||(e[r]={prev:u.current[r],next:o[r]});if(Object.keys(e).length>0){console.group(`[${r}] Re-rendered because:`);for(const[r,{prev:t,next:n}]of Object.entries(e))console.log(` ${r} changed:`),console.log(" prev:",t),console.log(" next:",n);console.groupEnd()}else console.log(`[${r}] Re-rendered with no prop changes (parent re-rendered)`)}u.current={...o}}})},exports.withSmartMemo=function(r,t){const o=e.memo(r,t||n);return o.displayName=`WithSmartMemo(${r.displayName||r.name})`,o};
2
+ //# sourceMappingURL=index.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/utils/isDev.ts","../src/utils/deepCompare.ts","../src/components/PerformanceProfiler.tsx","../src/hooks/useDebounce.ts","../src/hooks/useDeepCompareEffect.ts","../src/hooks/useDeepCompareMemo.ts","../src/hooks/useLazyRef.ts","../src/hooks/usePrevious.ts","../src/hooks/useRenderCount.ts","../src/hooks/useRenderTracker.ts","../src/hooks/useThrottle.ts","../src/hooks/useWhyDidYouRender.ts","../src/hoc/withSmartMemo.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,null,null,null,null,null],"names":["isDev","process","env","NODE_ENV","deepCompare","a","b","internalDeepCompare","WeakSet","seenA","seenB","isNaN","Date","getTime","RegExp","source","flags","Map","size","key","val","has","get","Set","add","Array","isArray","length","i","keysA","Object","keys","keysB","prototype","hasOwnProperty","call","children","id","onProfile","start","useRef","performance","now","useEffect","duration","current","console","log","toFixed","_jsx","_Fragment","value","delay","debounced","setDebounced","useState","handler","setTimeout","clearTimeout","effect","deps","prevDeps","signalRef","factory","useMemo","initializer","ref","initialized","count","componentName","options","renderCount","warnAfter","warn","throttled","setThrottled","lastRan","timerRef","elapsed","props","prevProps","changedProps","allKeys","prev","next","group","entries","groupEnd","Component","comparator","Memoized","React","memo","displayName","name"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * ReactPerfX — Lightweight React Performance Optimization Library
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ export { useRenderTracker, useDeepCompareEffect, useDeepCompareMemo, useDebounce, useThrottle, useWhyDidYouRender, usePrevious, useRenderCount, useLazyRef, } from "./hooks";
7
+ export { withSmartMemo } from "./hoc";
8
+ export { PerformanceProfiler } from "./components";
9
+ export { deepCompare, isDev } from "./utils";
10
+ export type { UseRenderTrackerOptions, ProfileMetrics, PerformanceProfilerProps, } from "./types";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EACH,gBAAgB,EAChB,oBAAoB,EACpB,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,kBAAkB,EAClB,WAAW,EACX,cAAc,EACd,UAAU,GACb,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAGtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAGnD,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAG7C,YAAY,EACR,uBAAuB,EACvB,cAAc,EACd,wBAAwB,GAC3B,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import e,{useRef as r,useEffect as n,useMemo as t,useState as o}from"react";import{jsx as c,Fragment as u}from"react/jsx-runtime";const i=()=>"development"===process.env.NODE_ENV;function s(e,t={}){const o=r(0);n(()=>{o.current++,i()&&(console.log(`[${e}] Render #${o.current}`),t.warnAfter&&o.current>t.warnAfter&&console.warn(`[${e}] Exceeded render threshold (${t.warnAfter})`))})}function f(e,r){return a(e,r,new WeakSet,new WeakSet)}function a(e,r,n,t){if(e===r)return!0;if("number"==typeof e&&"number"==typeof r&&isNaN(e)&&isNaN(r))return!0;if(null==e||null==r)return!1;if(typeof e!=typeof r)return!1;if("object"!=typeof e)return!1;if(e instanceof Date&&r instanceof Date)return e.getTime()===r.getTime();if(e instanceof Date!=r instanceof Date)return!1;if(e instanceof RegExp&&r instanceof RegExp)return e.source===r.source&&e.flags===r.flags;if(e instanceof RegExp!=r instanceof RegExp)return!1;if(e instanceof Map&&r instanceof Map){if(e.size!==r.size)return!1;for(const[o,c]of e)if(!r.has(o)||!a(c,r.get(o),n,t))return!1;return!0}if(e instanceof Map!=r instanceof Map)return!1;if(e instanceof Set&&r instanceof Set){if(e.size!==r.size)return!1;for(const n of e)if(!r.has(n))return!1;return!0}if(e instanceof Set!=r instanceof Set)return!1;if(n.has(e)&&t.has(r))return!0;if(n.has(e)||t.has(r))return!1;if(n.add(e),t.add(r),Array.isArray(e)&&Array.isArray(r)){if(e.length!==r.length)return!1;for(let o=0;o<e.length;o++)if(!a(e[o],r[o],n,t))return!1;return!0}if(Array.isArray(e)!==Array.isArray(r))return!1;const o=Object.keys(e),c=Object.keys(r);if(o.length!==c.length)return!1;for(const c of o)if(!Object.prototype.hasOwnProperty.call(r,c)||!a(e[c],r[c],n,t))return!1;return!0}function l(e,t){const o=r(),c=r(0);f(o.current,t)||(o.current=t,c.current++),n(e,[c.current])}function p(e,n){const o=r(),c=r(0);return f(o.current,n)||(o.current=n,c.current++),t(e,[c.current])}function d(e,r){const[t,c]=o(e);return n(()=>{const n=setTimeout(()=>c(e),r);return()=>clearTimeout(n)},[e,r]),t}function m(e,t){const[c,u]=o(e),i=r(Date.now()),s=r(null);return n(()=>{const r=Date.now(),n=r-i.current;return n>=t?(u(e),i.current=r):(s.current&&clearTimeout(s.current),s.current=setTimeout(()=>{u(e),i.current=Date.now()},t-n)),()=>{s.current&&clearTimeout(s.current)}},[e,t]),c}function g(e,t){const o=r();n(()=>{if(i()){if(o.current){const r={},n=new Set([...Object.keys(o.current),...Object.keys(t)]);for(const e of n)f(o.current[e],t[e])||(r[e]={prev:o.current[e],next:t[e]});if(Object.keys(r).length>0){console.group(`[${e}] Re-rendered because:`);for(const[e,{prev:n,next:t}]of Object.entries(r))console.log(` ${e} changed:`),console.log(" prev:",n),console.log(" next:",t);console.groupEnd()}else console.log(`[${e}] Re-rendered with no prop changes (parent re-rendered)`)}o.current={...t}}})}function y(e){const t=r();return n(()=>{t.current=e}),t.current}function h(){const e=r(0);return e.current++,e.current}function w(e){const n=r(null),t=r(!1);return t.current||(n.current=e(),t.current=!0),n}function b(r,n){const t=e.memo(r,n||f);return t.displayName=`WithSmartMemo(${r.displayName||r.name})`,t}const x=({children:e,id:t="Component",onProfile:o})=>{const s=r(performance.now());return n(()=>{const e=performance.now()-s.current;i()&&console.log(`[${t}] Render duration: ${e.toFixed(2)}ms`),o?.({id:t,duration:e}),s.current=performance.now()}),c(u,{children:e})};export{x as PerformanceProfiler,f as deepCompare,i as isDev,d as useDebounce,l as useDeepCompareEffect,p as useDeepCompareMemo,w as useLazyRef,y as usePrevious,h as useRenderCount,s as useRenderTracker,m as useThrottle,g as useWhyDidYouRender,b as withSmartMemo};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/utils/isDev.ts","../src/hooks/useRenderTracker.ts","../src/utils/deepCompare.ts","../src/hooks/useDeepCompareEffect.ts","../src/hooks/useDeepCompareMemo.ts","../src/hooks/useDebounce.ts","../src/hooks/useThrottle.ts","../src/hooks/useWhyDidYouRender.ts","../src/hooks/usePrevious.ts","../src/hooks/useRenderCount.ts","../src/hooks/useLazyRef.ts","../src/hoc/withSmartMemo.ts","../src/components/PerformanceProfiler.tsx"],"sourcesContent":[null,null,null,null,null,null,null,null,null,null,null,null,null],"names":["isDev","process","env","NODE_ENV","useRenderTracker","componentName","options","renderCount","useRef","useEffect","current","console","log","warnAfter","warn","deepCompare","a","b","internalDeepCompare","WeakSet","seenA","seenB","isNaN","Date","getTime","RegExp","source","flags","Map","size","key","val","has","get","Set","add","Array","isArray","length","i","keysA","Object","keys","keysB","prototype","hasOwnProperty","call","useDeepCompareEffect","effect","deps","prevDeps","signalRef","useDeepCompareMemo","factory","useMemo","useDebounce","value","delay","debounced","setDebounced","useState","handler","setTimeout","clearTimeout","useThrottle","throttled","setThrottled","lastRan","now","timerRef","elapsed","useWhyDidYouRender","props","prevProps","changedProps","allKeys","prev","next","group","entries","groupEnd","usePrevious","ref","useRenderCount","count","useLazyRef","initializer","initialized","withSmartMemo","Component","comparator","Memoized","React","memo","displayName","name","PerformanceProfiler","children","id","onProfile","start","performance","duration","toFixed","_jsx","_Fragment"],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Shared types for ReactPerfX
3
+ */
4
+ /** Options for useRenderTracker hook */
5
+ export interface UseRenderTrackerOptions {
6
+ /** Warn in console after this many renders */
7
+ warnAfter?: number;
8
+ }
9
+ /** Metrics returned by PerformanceProfiler */
10
+ export interface ProfileMetrics {
11
+ /** Identifier for the profiled component */
12
+ id: string;
13
+ /** Render duration in milliseconds */
14
+ duration: number;
15
+ }
16
+ /** Props for the PerformanceProfiler component */
17
+ export interface PerformanceProfilerProps {
18
+ /** Children to render and profile */
19
+ children: React.ReactNode;
20
+ /** Identifier for this profiler instance */
21
+ id?: string;
22
+ /** Callback invoked after each render with timing metrics */
23
+ onProfile?: (metrics: ProfileMetrics) => void;
24
+ }
25
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wCAAwC;AACxC,MAAM,WAAW,uBAAuB;IACpC,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,8CAA8C;AAC9C,MAAM,WAAW,cAAc;IAC3B,4CAA4C;IAC5C,EAAE,EAAE,MAAM,CAAC;IACX,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,kDAAkD;AAClD,MAAM,WAAW,wBAAwB;IACrC,qCAAqC;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,4CAA4C;IAC5C,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,6DAA6D;IAC7D,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;CACjD"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Deep comparison utility for ReactPerfX.
3
+ * Handles primitives, Date, RegExp, Map, Set, arrays, objects, NaN, and circular references.
4
+ */
5
+ export declare function deepCompare(a: any, b: any): boolean;
6
+ //# sourceMappingURL=deepCompare.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deepCompare.d.ts","sourceRoot":"","sources":["../../src/utils/deepCompare.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,OAAO,CAEnD"}
@@ -0,0 +1,3 @@
1
+ export { deepCompare } from "./deepCompare";
2
+ export { isDev } from "./isDev";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const isDev: () => boolean;
2
+ //# sourceMappingURL=isDev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isDev.d.ts","sourceRoot":"","sources":["../../src/utils/isDev.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,KAAK,eAA+C,CAAC"}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "react-perf-x",
3
+ "version": "0.1.0",
4
+ "description": "Lightweight React performance optimization library — hooks, HOCs, and utilities for detecting re-renders, smart memoization, and profiling.",
5
+ "main": "dist/index.cjs.js",
6
+ "module": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "sideEffects": false,
12
+ "scripts": {
13
+ "build": "rollup -c",
14
+ "build:ts": "tsc --noEmit",
15
+ "test": "jest",
16
+ "test:coverage": "jest --coverage",
17
+ "lint": "eslint \"src/**/*.{ts,tsx}\"",
18
+ "prepublishOnly": "npm run lint && npm test && npm run build"
19
+ },
20
+ "keywords": [
21
+ "react",
22
+ "performance",
23
+ "hooks",
24
+ "optimization",
25
+ "memoization",
26
+ "profiler",
27
+ "re-render",
28
+ "debounce",
29
+ "throttle",
30
+ "deep-compare"
31
+ ],
32
+ "author": "Open Source",
33
+ "license": "MIT",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "https://github.com/sujalsarnobat/ReactPerfX.git"
37
+ },
38
+ "devDependencies": {
39
+ "typescript": "^5.0.0",
40
+ "jest": "^29.0.0",
41
+ "ts-jest": "^29.0.0",
42
+ "@types/jest": "^29.0.0",
43
+ "jest-environment-jsdom": "^29.0.0",
44
+ "eslint": "^8.0.0",
45
+ "@typescript-eslint/eslint-plugin": "^6.0.0",
46
+ "@typescript-eslint/parser": "^6.0.0",
47
+ "react": "^18.0.0",
48
+ "@types/react": "^18.0.0",
49
+ "react-dom": "^18.0.0",
50
+ "@types/react-dom": "^18.0.0",
51
+ "@testing-library/react": "^14.0.0",
52
+ "rollup": "^4.0.0",
53
+ "@rollup/plugin-node-resolve": "^15.0.0",
54
+ "@rollup/plugin-typescript": "^11.0.0",
55
+ "@rollup/plugin-terser": "^0.4.0",
56
+ "tslib": "^2.6.0"
57
+ },
58
+ "peerDependencies": {
59
+ "react": ">=18.0.0",
60
+ "react-dom": ">=18.0.0"
61
+ }
62
+ }