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.
- package/LICENSE +21 -0
- package/README.md +170 -0
- package/dist/components/PerformanceProfiler.d.ts +13 -0
- package/dist/components/PerformanceProfiler.d.ts.map +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/hoc/index.d.ts +2 -0
- package/dist/hoc/index.d.ts.map +1 -0
- package/dist/hoc/withSmartMemo.d.ts +12 -0
- package/dist/hoc/withSmartMemo.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +10 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/useDebounce.d.ts +2 -0
- package/dist/hooks/useDebounce.d.ts.map +1 -0
- package/dist/hooks/useDeepCompareEffect.d.ts +12 -0
- package/dist/hooks/useDeepCompareEffect.d.ts.map +1 -0
- package/dist/hooks/useDeepCompareMemo.d.ts +12 -0
- package/dist/hooks/useDeepCompareMemo.d.ts.map +1 -0
- package/dist/hooks/useLazyRef.d.ts +11 -0
- package/dist/hooks/useLazyRef.d.ts.map +1 -0
- package/dist/hooks/usePrevious.d.ts +9 -0
- package/dist/hooks/usePrevious.d.ts.map +1 -0
- package/dist/hooks/useRenderCount.d.ts +11 -0
- package/dist/hooks/useRenderCount.d.ts.map +1 -0
- package/dist/hooks/useRenderTracker.d.ts +10 -0
- package/dist/hooks/useRenderTracker.d.ts.map +1 -0
- package/dist/hooks/useThrottle.d.ts +7 -0
- package/dist/hooks/useThrottle.d.ts.map +1 -0
- package/dist/hooks/useWhyDidYouRender.d.ts +13 -0
- package/dist/hooks/useWhyDidYouRender.d.ts.map +1 -0
- package/dist/index.cjs.js +2 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/deepCompare.d.ts +6 -0
- package/dist/utils/deepCompare.d.ts.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/isDev.d.ts +2 -0
- package/dist/utils/isDev.d.ts.map +1 -0
- 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
|
+
[](https://github.com/sujalsarnobat/ReactPerfX/actions)
|
|
6
|
+
[](https://www.npmjs.com/package/react-perf-x)
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
[](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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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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"}
|
package/dist/types.d.ts
ADDED
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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
|
+
}
|