@usefy/use-memory-monitor 0.0.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/README.md +612 -0
- package/dist/index.d.mts +537 -0
- package/dist/index.d.ts +537 -0
- package/dist/index.js +1114 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1077 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +62 -0
package/README.md
ADDED
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/mirunamu00/usefy/master/assets/logo.png" alt="usefy logo" width="120" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">@usefy/use-memory-monitor</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Advanced React hook for real-time browser memory monitoring</strong>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/@usefy/use-memory-monitor">
|
|
13
|
+
<img src="https://img.shields.io/npm/v/@usefy/use-memory-monitor.svg?style=flat-square&color=007acc" alt="npm version" />
|
|
14
|
+
</a>
|
|
15
|
+
<a href="https://www.npmjs.com/package/@usefy/use-memory-monitor">
|
|
16
|
+
<img src="https://img.shields.io/npm/dm/@usefy/use-memory-monitor.svg?style=flat-square&color=007acc" alt="npm downloads" />
|
|
17
|
+
</a>
|
|
18
|
+
<a href="https://bundlephobia.com/package/@usefy/use-memory-monitor">
|
|
19
|
+
<img src="https://img.shields.io/bundlephobia/minzip/@usefy/use-memory-monitor?style=flat-square&color=007acc" alt="bundle size" />
|
|
20
|
+
</a>
|
|
21
|
+
<a href="https://github.com/mirunamu00/usefy/blob/master/LICENSE">
|
|
22
|
+
<img src="https://img.shields.io/npm/l/@usefy/use-memory-monitor.svg?style=flat-square&color=007acc" alt="license" />
|
|
23
|
+
</a>
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
<p align="center">
|
|
27
|
+
<a href="#installation">Installation</a> •
|
|
28
|
+
<a href="#quick-start">Quick Start</a> •
|
|
29
|
+
<a href="#api-reference">API Reference</a> •
|
|
30
|
+
<a href="#examples">Examples</a> •
|
|
31
|
+
<a href="#browser-support">Browser Support</a> •
|
|
32
|
+
<a href="#license">License</a>
|
|
33
|
+
</p>
|
|
34
|
+
|
|
35
|
+
<p align="center">
|
|
36
|
+
<a href="https://mirunamu00.github.io/usefy/?path=/docs/hooks-usememorymonitor--docs" target="_blank" rel="noopener noreferrer">
|
|
37
|
+
<strong>📚 View Storybook Demo</strong>
|
|
38
|
+
</a>
|
|
39
|
+
</p>
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Overview
|
|
44
|
+
|
|
45
|
+
`@usefy/use-memory-monitor` is a comprehensive React hook for monitoring browser memory usage in real-time. It provides heap metrics, memory leak detection, threshold-based alerts, history tracking, and snapshot comparison capabilities.
|
|
46
|
+
|
|
47
|
+
**Part of the [@usefy](https://www.npmjs.com/org/usefy) ecosystem** — a collection of production-ready React hooks designed for modern applications.
|
|
48
|
+
|
|
49
|
+
### Why use-memory-monitor?
|
|
50
|
+
|
|
51
|
+
- **Real-time Monitoring** — Track heap usage, total heap, and memory limits in real-time
|
|
52
|
+
- **Leak Detection** — Automatic memory leak detection using linear regression analysis
|
|
53
|
+
- **Threshold Alerts** — Configure custom thresholds for low/medium/high/critical severity levels
|
|
54
|
+
- **Memory Snapshots** — Take snapshots and compare memory usage between different points in time
|
|
55
|
+
- **History Tracking** — Maintain a circular buffer of historical memory data with trend analysis
|
|
56
|
+
- **Tab Visibility Optimization** — Automatically pauses monitoring when tab is hidden
|
|
57
|
+
- **TypeScript First** — Full type safety with comprehensive exported interfaces
|
|
58
|
+
- **SSR Compatible** — Safe to use with Next.js, Remix, and other SSR frameworks
|
|
59
|
+
- **Browser Fallbacks** — Graceful degradation in browsers without full API support
|
|
60
|
+
- **Well Tested** — Comprehensive test coverage (175 tests) with Vitest
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Installation
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# npm
|
|
68
|
+
npm install @usefy/use-memory-monitor
|
|
69
|
+
|
|
70
|
+
# yarn
|
|
71
|
+
yarn add @usefy/use-memory-monitor
|
|
72
|
+
|
|
73
|
+
# pnpm
|
|
74
|
+
pnpm add @usefy/use-memory-monitor
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Peer Dependencies
|
|
78
|
+
|
|
79
|
+
This package requires React 18 or 19:
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"peerDependencies": {
|
|
84
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Quick Start
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
import { useMemoryMonitor } from "@usefy/use-memory-monitor";
|
|
95
|
+
|
|
96
|
+
function MemoryMonitor() {
|
|
97
|
+
const {
|
|
98
|
+
heapUsed,
|
|
99
|
+
heapTotal,
|
|
100
|
+
heapLimit,
|
|
101
|
+
isSupported,
|
|
102
|
+
severity,
|
|
103
|
+
formatted,
|
|
104
|
+
} = useMemoryMonitor({
|
|
105
|
+
interval: 1000,
|
|
106
|
+
autoStart: true,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
if (!isSupported) {
|
|
110
|
+
return <div>Memory monitoring not supported in this browser</div>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<div>
|
|
115
|
+
<h2>Memory Usage</h2>
|
|
116
|
+
<p>Heap Used: {formatted.heapUsed}</p>
|
|
117
|
+
<p>Heap Total: {formatted.heapTotal}</p>
|
|
118
|
+
<p>Heap Limit: {formatted.heapLimit}</p>
|
|
119
|
+
<p>Severity: {severity}</p>
|
|
120
|
+
</div>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Browser Support
|
|
128
|
+
|
|
129
|
+
### Full Support (performance.memory API)
|
|
130
|
+
- ✅ **Chrome** (all versions)
|
|
131
|
+
- ✅ **Edge** (Chromium-based)
|
|
132
|
+
|
|
133
|
+
### Limited Support (DOM-only metrics)
|
|
134
|
+
- ⚠️ **Firefox** - DOM tracking only, no heap metrics
|
|
135
|
+
- ⚠️ **Safari** - DOM tracking only, no heap metrics
|
|
136
|
+
- ⚠️ **Other browsers** - Fallback strategies available
|
|
137
|
+
|
|
138
|
+
### Browser Detection
|
|
139
|
+
|
|
140
|
+
The hook automatically detects browser capabilities and adjusts functionality:
|
|
141
|
+
|
|
142
|
+
```tsx
|
|
143
|
+
const { isSupported, getUnsupportedInfo, getBrowserSupport } = useMemoryMonitor();
|
|
144
|
+
|
|
145
|
+
if (!isSupported) {
|
|
146
|
+
const info = getUnsupportedInfo();
|
|
147
|
+
console.log("Reason:", info.reason); // 'no-api' | 'browser-restriction' | etc.
|
|
148
|
+
console.log("Browser:", info.browser);
|
|
149
|
+
console.log("Fallbacks:", info.availableFallbacks);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const support = getBrowserSupport();
|
|
153
|
+
console.log("Support level:", support.level); // 'full' | 'partial' | 'none'
|
|
154
|
+
console.log("Available metrics:", support.availableMetrics);
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## API Reference
|
|
160
|
+
|
|
161
|
+
### `useMemoryMonitor(options?)`
|
|
162
|
+
|
|
163
|
+
A hook that monitors browser memory usage in real-time with leak detection and threshold alerts.
|
|
164
|
+
|
|
165
|
+
#### Parameters
|
|
166
|
+
|
|
167
|
+
| Parameter | Type | Default | Description |
|
|
168
|
+
| --------- | ----------------------------- | ------- | ---------------------------------- |
|
|
169
|
+
| `options` | `UseMemoryMonitorOptions` | `{}` | Configuration options (see below) |
|
|
170
|
+
|
|
171
|
+
#### Options (`UseMemoryMonitorOptions`)
|
|
172
|
+
|
|
173
|
+
| Option | Type | Default | Description |
|
|
174
|
+
| -------------------- | ----------------------- | -------- | ------------------------------------------------ |
|
|
175
|
+
| `interval` | `number` | `1000` | Polling interval in milliseconds |
|
|
176
|
+
| `autoStart` | `boolean` | `true` | Start monitoring automatically on mount |
|
|
177
|
+
| `enabled` | `boolean` | `true` | Enable/disable the hook |
|
|
178
|
+
| `enableHistory` | `boolean` | `true` | Track memory history |
|
|
179
|
+
| `historySize` | `number` | `50` | Maximum number of history entries |
|
|
180
|
+
| `thresholds` | `ThresholdOptions` | See below | Memory usage thresholds |
|
|
181
|
+
| `leakDetection` | `LeakDetectionOptions` | See below | Leak detection configuration |
|
|
182
|
+
| `pauseWhenHidden` | `boolean` | `true` | Pause monitoring when tab is hidden |
|
|
183
|
+
| `onThresholdChange` | `(severity) => void` | - | Callback when severity level changes |
|
|
184
|
+
| `onMemoryUpdate` | `(memory) => void` | - | Callback on each memory update |
|
|
185
|
+
| `onLeakDetected` | `(analysis) => void` | - | Callback when memory leak is detected |
|
|
186
|
+
| `onUnsupported` | `(info) => void` | - | Callback when memory API is not supported |
|
|
187
|
+
|
|
188
|
+
##### Default Thresholds
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
{
|
|
192
|
+
medium: 60, // Yellow alert at 60% usage
|
|
193
|
+
high: 80, // Orange alert at 80% usage
|
|
194
|
+
critical: 90, // Red alert at 90% usage
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
##### Default Leak Detection
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
{
|
|
202
|
+
enabled: true,
|
|
203
|
+
sensitivity: "medium", // 'low' | 'medium' | 'high'
|
|
204
|
+
sampleSize: 10,
|
|
205
|
+
minDuration: 30000, // 30 seconds
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
#### Returns `UseMemoryMonitorReturn`
|
|
210
|
+
|
|
211
|
+
| Property | Type | Description |
|
|
212
|
+
| ---------------------- | ------------------------------------ | -------------------------------------------- |
|
|
213
|
+
| `memory` | `MemoryInfo \| null` | Current memory information |
|
|
214
|
+
| `heapUsed` | `number \| null` | Used heap size in bytes |
|
|
215
|
+
| `heapTotal` | `number \| null` | Total heap size in bytes |
|
|
216
|
+
| `heapLimit` | `number \| null` | Heap size limit in bytes |
|
|
217
|
+
| `isSupported` | `boolean` | Whether memory monitoring is supported |
|
|
218
|
+
| `isMonitoring` | `boolean` | Whether currently monitoring |
|
|
219
|
+
| `isLeakDetected` | `boolean` | Whether memory leak is detected |
|
|
220
|
+
| `severity` | `Severity` | Current severity level |
|
|
221
|
+
| `history` | `MemoryInfo[]` | Historical memory data |
|
|
222
|
+
| `trend` | `Trend` | Memory usage trend |
|
|
223
|
+
| `formatted` | `FormattedMemory` | Human-readable formatted values |
|
|
224
|
+
| `start` | `() => void` | Start monitoring |
|
|
225
|
+
| `stop` | `() => void` | Stop monitoring |
|
|
226
|
+
| `takeSnapshot` | `(id: string) => MemorySnapshot \| null` | Take a memory snapshot |
|
|
227
|
+
| `compareSnapshots` | `(id1, id2) => MemoryDifference \| null` | Compare two snapshots |
|
|
228
|
+
| `clearSnapshots` | `() => void` | Clear all snapshots |
|
|
229
|
+
| `getAllSnapshots` | `() => MemorySnapshot[]` | Get all snapshots |
|
|
230
|
+
| `clearHistory` | `() => void` | Clear history buffer |
|
|
231
|
+
| `getLeakAnalysis` | `() => LeakAnalysis \| null` | Get current leak analysis |
|
|
232
|
+
| `getBrowserSupport` | `() => BrowserSupport` | Get browser support information |
|
|
233
|
+
| `getUnsupportedInfo` | `() => UnsupportedInfo` | Get info about why monitoring is unsupported |
|
|
234
|
+
|
|
235
|
+
### Types
|
|
236
|
+
|
|
237
|
+
#### `Severity`
|
|
238
|
+
```typescript
|
|
239
|
+
type Severity = "low" | "medium" | "high" | "critical";
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
#### `Trend`
|
|
243
|
+
```typescript
|
|
244
|
+
type Trend = "increasing" | "stable" | "decreasing";
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
#### `MemoryInfo`
|
|
248
|
+
```typescript
|
|
249
|
+
interface MemoryInfo {
|
|
250
|
+
heapUsed: number | null;
|
|
251
|
+
heapTotal: number | null;
|
|
252
|
+
heapLimit: number | null;
|
|
253
|
+
timestamp: number;
|
|
254
|
+
domNodes?: number | null;
|
|
255
|
+
eventListeners?: number | null;
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
#### `FormattedMemory`
|
|
260
|
+
```typescript
|
|
261
|
+
interface FormattedMemory {
|
|
262
|
+
heapUsed: string;
|
|
263
|
+
heapTotal: string;
|
|
264
|
+
heapLimit: string;
|
|
265
|
+
domNodes?: string;
|
|
266
|
+
eventListeners?: string;
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Examples
|
|
273
|
+
|
|
274
|
+
### Basic Memory Monitoring
|
|
275
|
+
|
|
276
|
+
```tsx
|
|
277
|
+
import { useMemoryMonitor } from "@usefy/use-memory-monitor";
|
|
278
|
+
|
|
279
|
+
function BasicMonitor() {
|
|
280
|
+
const { formatted, severity, isMonitoring, start, stop } = useMemoryMonitor({
|
|
281
|
+
interval: 1000,
|
|
282
|
+
autoStart: true,
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
return (
|
|
286
|
+
<div>
|
|
287
|
+
<h2>Memory Usage</h2>
|
|
288
|
+
<p>Used: {formatted.heapUsed}</p>
|
|
289
|
+
<p>Total: {formatted.heapTotal}</p>
|
|
290
|
+
<p>Severity: {severity}</p>
|
|
291
|
+
|
|
292
|
+
<button onClick={isMonitoring ? stop : start}>
|
|
293
|
+
{isMonitoring ? "Stop" : "Start"}
|
|
294
|
+
</button>
|
|
295
|
+
</div>
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Memory Leak Detection
|
|
301
|
+
|
|
302
|
+
```tsx
|
|
303
|
+
import { useMemoryMonitor } from "@usefy/use-memory-monitor";
|
|
304
|
+
|
|
305
|
+
function LeakDetector() {
|
|
306
|
+
const { isLeakDetected, getLeakAnalysis, formatted } = useMemoryMonitor({
|
|
307
|
+
interval: 1000,
|
|
308
|
+
leakDetection: {
|
|
309
|
+
enabled: true,
|
|
310
|
+
sensitivity: "high",
|
|
311
|
+
sampleSize: 15,
|
|
312
|
+
minDuration: 20000, // 20 seconds
|
|
313
|
+
},
|
|
314
|
+
onLeakDetected: (analysis) => {
|
|
315
|
+
console.warn("Memory leak detected!", {
|
|
316
|
+
probability: analysis.probability,
|
|
317
|
+
confidence: analysis.confidence,
|
|
318
|
+
slope: analysis.slope,
|
|
319
|
+
});
|
|
320
|
+
},
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
const analysis = getLeakAnalysis();
|
|
324
|
+
|
|
325
|
+
return (
|
|
326
|
+
<div>
|
|
327
|
+
<h2>Leak Detection</h2>
|
|
328
|
+
{isLeakDetected && (
|
|
329
|
+
<div className="alert">
|
|
330
|
+
⚠️ Memory leak detected!
|
|
331
|
+
<p>Probability: {(analysis?.probability ?? 0).toFixed(2)}%</p>
|
|
332
|
+
<p>Confidence: {analysis?.confidence}</p>
|
|
333
|
+
</div>
|
|
334
|
+
)}
|
|
335
|
+
<p>Current Usage: {formatted.heapUsed}</p>
|
|
336
|
+
</div>
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Threshold Alerts
|
|
342
|
+
|
|
343
|
+
```tsx
|
|
344
|
+
import { useMemoryMonitor } from "@usefy/use-memory-monitor";
|
|
345
|
+
|
|
346
|
+
function ThresholdMonitor() {
|
|
347
|
+
const { severity, heapUsed, heapLimit, formatted } = useMemoryMonitor({
|
|
348
|
+
interval: 1000,
|
|
349
|
+
thresholds: {
|
|
350
|
+
medium: 50,
|
|
351
|
+
high: 75,
|
|
352
|
+
critical: 90,
|
|
353
|
+
},
|
|
354
|
+
onThresholdChange: (newSeverity) => {
|
|
355
|
+
if (newSeverity === "critical") {
|
|
356
|
+
alert("Critical memory usage!");
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
const usagePercent = heapUsed && heapLimit
|
|
362
|
+
? (heapUsed / heapLimit) * 100
|
|
363
|
+
: 0;
|
|
364
|
+
|
|
365
|
+
return (
|
|
366
|
+
<div>
|
|
367
|
+
<h2>Memory Usage: {usagePercent.toFixed(1)}%</h2>
|
|
368
|
+
<div className={`alert alert-${severity}`}>
|
|
369
|
+
Severity: {severity}
|
|
370
|
+
</div>
|
|
371
|
+
<p>{formatted.heapUsed} / {formatted.heapLimit}</p>
|
|
372
|
+
</div>
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Memory Snapshots
|
|
378
|
+
|
|
379
|
+
```tsx
|
|
380
|
+
import { useMemoryMonitor } from "@usefy/use-memory-monitor";
|
|
381
|
+
import { useState } from "react";
|
|
382
|
+
|
|
383
|
+
function SnapshotComparison() {
|
|
384
|
+
const {
|
|
385
|
+
takeSnapshot,
|
|
386
|
+
compareSnapshots,
|
|
387
|
+
getAllSnapshots,
|
|
388
|
+
clearSnapshots,
|
|
389
|
+
formatted,
|
|
390
|
+
} = useMemoryMonitor({ interval: 1000 });
|
|
391
|
+
|
|
392
|
+
const [snapshots, setSnapshots] = useState<string[]>([]);
|
|
393
|
+
|
|
394
|
+
const handleSnapshot = () => {
|
|
395
|
+
const snapshot = takeSnapshot(`snapshot-${Date.now()}`);
|
|
396
|
+
if (snapshot) {
|
|
397
|
+
setSnapshots([...snapshots, snapshot.id]);
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
const handleCompare = () => {
|
|
402
|
+
if (snapshots.length >= 2) {
|
|
403
|
+
const diff = compareSnapshots(snapshots[0], snapshots[snapshots.length - 1]);
|
|
404
|
+
if (diff) {
|
|
405
|
+
console.log("Memory difference:", {
|
|
406
|
+
heapUsed: (diff.heapUsed / 1024 / 1024).toFixed(2) + " MB",
|
|
407
|
+
heapTotal: (diff.heapTotal / 1024 / 1024).toFixed(2) + " MB",
|
|
408
|
+
duration: (diff.duration / 1000).toFixed(1) + " seconds",
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
return (
|
|
415
|
+
<div>
|
|
416
|
+
<h2>Snapshots ({snapshots.length})</h2>
|
|
417
|
+
<p>Current: {formatted.heapUsed}</p>
|
|
418
|
+
|
|
419
|
+
<button onClick={handleSnapshot}>Take Snapshot</button>
|
|
420
|
+
<button onClick={handleCompare} disabled={snapshots.length < 2}>
|
|
421
|
+
Compare First & Last
|
|
422
|
+
</button>
|
|
423
|
+
<button onClick={clearSnapshots}>Clear All</button>
|
|
424
|
+
|
|
425
|
+
<ul>
|
|
426
|
+
{getAllSnapshots().map((snapshot) => (
|
|
427
|
+
<li key={snapshot.id}>
|
|
428
|
+
{snapshot.id}: {(snapshot.data.heapUsed || 0) / 1024 / 1024} MB
|
|
429
|
+
</li>
|
|
430
|
+
))}
|
|
431
|
+
</ul>
|
|
432
|
+
</div>
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
### History & Trend Analysis
|
|
438
|
+
|
|
439
|
+
```tsx
|
|
440
|
+
import { useMemoryMonitor } from "@usefy/use-memory-monitor";
|
|
441
|
+
|
|
442
|
+
function HistoryTracker() {
|
|
443
|
+
const { history, trend, formatted, clearHistory } = useMemoryMonitor({
|
|
444
|
+
interval: 500,
|
|
445
|
+
enableHistory: true,
|
|
446
|
+
historySize: 30,
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
const maxHeapUsed = Math.max(...history.map((h) => h.heapUsed || 0), 1);
|
|
450
|
+
|
|
451
|
+
return (
|
|
452
|
+
<div>
|
|
453
|
+
<h2>Memory History</h2>
|
|
454
|
+
<p>Current: {formatted.heapUsed}</p>
|
|
455
|
+
<p>
|
|
456
|
+
Trend: {trend === "increasing" ? "↗" : trend === "decreasing" ? "↘" : "→"} {trend}
|
|
457
|
+
</p>
|
|
458
|
+
<p>History Points: {history.length}</p>
|
|
459
|
+
|
|
460
|
+
<button onClick={clearHistory}>Clear History</button>
|
|
461
|
+
|
|
462
|
+
{/* Simple bar chart */}
|
|
463
|
+
<div style={{ display: "flex", alignItems: "flex-end", height: 100 }}>
|
|
464
|
+
{history.map((point, i) => {
|
|
465
|
+
const heightPercent = ((point.heapUsed || 0) / maxHeapUsed) * 100;
|
|
466
|
+
return (
|
|
467
|
+
<div
|
|
468
|
+
key={i}
|
|
469
|
+
style={{
|
|
470
|
+
flex: 1,
|
|
471
|
+
height: `${heightPercent}%`,
|
|
472
|
+
backgroundColor: "blue",
|
|
473
|
+
margin: "0 1px",
|
|
474
|
+
}}
|
|
475
|
+
title={`${((point.heapUsed || 0) / 1024 / 1024).toFixed(2)} MB`}
|
|
476
|
+
/>
|
|
477
|
+
);
|
|
478
|
+
})}
|
|
479
|
+
</div>
|
|
480
|
+
</div>
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### Browser Support Detection
|
|
486
|
+
|
|
487
|
+
```tsx
|
|
488
|
+
import { useMemoryMonitor } from "@usefy/use-memory-monitor";
|
|
489
|
+
|
|
490
|
+
function SupportDetection() {
|
|
491
|
+
const { isSupported, getUnsupportedInfo, getBrowserSupport } = useMemoryMonitor();
|
|
492
|
+
|
|
493
|
+
if (!isSupported) {
|
|
494
|
+
const info = getUnsupportedInfo();
|
|
495
|
+
return (
|
|
496
|
+
<div>
|
|
497
|
+
<h2>Limited Support</h2>
|
|
498
|
+
<p>Reason: {info.reason}</p>
|
|
499
|
+
<p>Browser: {info.browser || "Unknown"}</p>
|
|
500
|
+
<p>Available fallbacks: {info.availableFallbacks.join(", ")}</p>
|
|
501
|
+
</div>
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
const support = getBrowserSupport();
|
|
506
|
+
|
|
507
|
+
return (
|
|
508
|
+
<div>
|
|
509
|
+
<h2>Browser Support</h2>
|
|
510
|
+
<p>Level: {support.level}</p>
|
|
511
|
+
<p>Available metrics: {support.availableMetrics.join(", ")}</p>
|
|
512
|
+
<p>Secure context: {support.isSecureContext ? "Yes" : "No"}</p>
|
|
513
|
+
<p>Cross-origin isolated: {support.isCrossOriginIsolated ? "Yes" : "No"}</p>
|
|
514
|
+
{support.limitations.length > 0 && (
|
|
515
|
+
<ul>
|
|
516
|
+
{support.limitations.map((limitation, i) => (
|
|
517
|
+
<li key={i}>{limitation}</li>
|
|
518
|
+
))}
|
|
519
|
+
</ul>
|
|
520
|
+
)}
|
|
521
|
+
</div>
|
|
522
|
+
);
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
---
|
|
527
|
+
|
|
528
|
+
## Performance
|
|
529
|
+
|
|
530
|
+
### Optimizations
|
|
531
|
+
|
|
532
|
+
1. **Tab Visibility**: Automatically pauses monitoring when tab is hidden (configurable with `pauseWhenHidden`)
|
|
533
|
+
2. **Circular Buffer**: Uses efficient circular buffer for history storage (O(1) operations)
|
|
534
|
+
3. **Stable References**: All callback functions are memoized with `useCallback`
|
|
535
|
+
4. **useSyncExternalStore**: React 18+ concurrent mode safe state management
|
|
536
|
+
5. **Minimal Re-renders**: Only triggers re-renders when actual memory data changes
|
|
537
|
+
|
|
538
|
+
### Bundle Size
|
|
539
|
+
|
|
540
|
+
The hook is lightweight and tree-shakeable:
|
|
541
|
+
- Main hook: ~8KB minified
|
|
542
|
+
- With all utilities: ~15KB minified
|
|
543
|
+
- Gzipped: ~5KB
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## TypeScript
|
|
548
|
+
|
|
549
|
+
This hook is written in TypeScript and exports comprehensive type definitions:
|
|
550
|
+
|
|
551
|
+
```tsx
|
|
552
|
+
import {
|
|
553
|
+
useMemoryMonitor,
|
|
554
|
+
type UseMemoryMonitorOptions,
|
|
555
|
+
type UseMemoryMonitorReturn,
|
|
556
|
+
type MemoryInfo,
|
|
557
|
+
type MemorySnapshot,
|
|
558
|
+
type LeakAnalysis,
|
|
559
|
+
type BrowserSupport,
|
|
560
|
+
type Severity,
|
|
561
|
+
type Trend,
|
|
562
|
+
} from "@usefy/use-memory-monitor";
|
|
563
|
+
|
|
564
|
+
// Full type safety
|
|
565
|
+
const options: UseMemoryMonitorOptions = {
|
|
566
|
+
interval: 1000,
|
|
567
|
+
autoStart: true,
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
const monitor: UseMemoryMonitorReturn = useMemoryMonitor(options);
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
---
|
|
574
|
+
|
|
575
|
+
## Testing
|
|
576
|
+
|
|
577
|
+
This package maintains comprehensive test coverage to ensure reliability and stability.
|
|
578
|
+
|
|
579
|
+
### Test Coverage
|
|
580
|
+
|
|
581
|
+
📊 **175 tests passed** covering:
|
|
582
|
+
- Memory monitoring functionality
|
|
583
|
+
- Leak detection algorithms
|
|
584
|
+
- Snapshot management
|
|
585
|
+
- Browser support detection
|
|
586
|
+
- Circular buffer operations
|
|
587
|
+
- Formatting utilities
|
|
588
|
+
- SSR compatibility
|
|
589
|
+
|
|
590
|
+
### Test Categories
|
|
591
|
+
|
|
592
|
+
- **Initialization & Lifecycle**: Mount, unmount, start/stop behavior
|
|
593
|
+
- **Memory Tracking**: Polling, history, trend analysis
|
|
594
|
+
- **Leak Detection**: Linear regression, sensitivity levels, analysis
|
|
595
|
+
- **Thresholds**: Severity calculation, callbacks
|
|
596
|
+
- **Snapshots**: Create, compare, clear operations
|
|
597
|
+
- **Browser Detection**: API availability, fallback strategies
|
|
598
|
+
- **Edge Cases**: SSR, unsupported browsers, invalid inputs
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
602
|
+
## License
|
|
603
|
+
|
|
604
|
+
MIT © [mirunamu](https://github.com/mirunamu00)
|
|
605
|
+
|
|
606
|
+
This package is part of the [usefy](https://github.com/mirunamu00/usefy) monorepo.
|
|
607
|
+
|
|
608
|
+
---
|
|
609
|
+
|
|
610
|
+
<p align="center">
|
|
611
|
+
<sub>Built with care by the usefy team</sub>
|
|
612
|
+
</p>
|