react-render-detective 0.3.0 → 0.5.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/CHANGELOG.md +244 -0
- package/README.md +1 -1
- package/dist/{chunk-QOGTEVBP.js → chunk-DI5STJM4.js} +39 -3
- package/dist/chunk-DI5STJM4.js.map +1 -0
- package/dist/chunk-H5RG2EPP.cjs +75 -0
- package/dist/chunk-H5RG2EPP.cjs.map +1 -0
- package/dist/chunk-LILK23YH.js +71 -0
- package/dist/chunk-LILK23YH.js.map +1 -0
- package/dist/{chunk-DZ3BZ654.cjs → chunk-OSPTERGK.cjs} +39 -3
- package/dist/chunk-OSPTERGK.cjs.map +1 -0
- package/dist/core.cjs +18 -18
- package/dist/core.d.cts +14 -0
- package/dist/core.d.ts +14 -0
- package/dist/core.js +1 -1
- package/dist/index.cjs +466 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +160 -2
- package/dist/index.d.ts +160 -2
- package/dist/index.js +429 -24
- package/dist/index.js.map +1 -1
- package/dist/overlay.cjs +2 -2
- package/dist/overlay.js +1 -1
- package/dist/testing.cjs +20 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +62 -0
- package/dist/testing.d.ts +62 -0
- package/dist/testing.js +3 -0
- package/dist/testing.js.map +1 -0
- package/package.json +14 -4
- package/dist/chunk-DZ3BZ654.cjs.map +0 -1
- package/dist/chunk-QOGTEVBP.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,130 @@
|
|
|
1
|
-
import { b as RenderEvent,
|
|
1
|
+
import { b as RenderEvent, j as Confidence, R as RenderReason, a as DetectiveOptions, D as DetectiveConfig, A as AppStats, d as ComponentStats } from './types-gl13xwmN.js';
|
|
2
2
|
export { i as ComponentInfo, C as ContextChange, f as Diagnosis, I as Inspected, g as InspectionLimits, M as Mode, P as PropChange, k as PropChangeKind, h as PropValueType, c as RenderPhase, l as RenderTimings, e as Thresholds, T as TrackedStateChange } from './types-gl13xwmN.js';
|
|
3
|
+
import { RenderProfile } from './testing.js';
|
|
3
4
|
import { ComponentType, ReactNode, Dispatch, SetStateAction } from 'react';
|
|
4
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Interaction-scoped attribution.
|
|
8
|
+
*
|
|
9
|
+
* Performance is felt per interaction, not in aggregate — and INP is the metric
|
|
10
|
+
* teams are actually judged on. This joins the two halves: the browser says a
|
|
11
|
+
* keystroke took 240ms, and the render events say which components spent it and
|
|
12
|
+
* why.
|
|
13
|
+
*
|
|
14
|
+
* Uses `PerformanceObserver` with `event` timing, a public browser API. Where it
|
|
15
|
+
* is unsupported (older Safari, jsdom) interaction tracking simply stays empty
|
|
16
|
+
* rather than guessing.
|
|
17
|
+
*/
|
|
18
|
+
interface InteractionRecord {
|
|
19
|
+
id: string;
|
|
20
|
+
/** `click`, `keydown`, `pointerup`… */
|
|
21
|
+
type: string;
|
|
22
|
+
/** Best-effort description of what was interacted with. */
|
|
23
|
+
target?: string;
|
|
24
|
+
startTime: number;
|
|
25
|
+
/** Browser-reported event duration — the number INP is computed from. */
|
|
26
|
+
durationMs: number;
|
|
27
|
+
/**
|
|
28
|
+
* For a manually measured interaction: how long the synchronous action took.
|
|
29
|
+
* Immune to throttling, unlike the full window, which waits on a frame.
|
|
30
|
+
*/
|
|
31
|
+
handlerMs?: number;
|
|
32
|
+
/** Renders committed inside this interaction's window. */
|
|
33
|
+
renders: RenderEvent[];
|
|
34
|
+
/** Sum of self durations for those renders. */
|
|
35
|
+
renderTimeMs: number;
|
|
36
|
+
/** Render time that no observable input change explains. */
|
|
37
|
+
avoidableRenderTimeMs: number;
|
|
38
|
+
}
|
|
39
|
+
interface InteractionSummary {
|
|
40
|
+
interaction: InteractionRecord;
|
|
41
|
+
/** Components ordered by cost within this interaction. */
|
|
42
|
+
contributors: Array<{
|
|
43
|
+
component: string;
|
|
44
|
+
source?: string;
|
|
45
|
+
renders: number;
|
|
46
|
+
totalMs: number;
|
|
47
|
+
cause: string;
|
|
48
|
+
}>;
|
|
49
|
+
headline: string;
|
|
50
|
+
nextStep: string;
|
|
51
|
+
confidence: Confidence;
|
|
52
|
+
}
|
|
53
|
+
interface RawEventTiming {
|
|
54
|
+
name: string;
|
|
55
|
+
startTime: number;
|
|
56
|
+
duration: number;
|
|
57
|
+
target?: string;
|
|
58
|
+
handlerMs?: number;
|
|
59
|
+
}
|
|
60
|
+
declare class InteractionTracker {
|
|
61
|
+
private capacity;
|
|
62
|
+
private records;
|
|
63
|
+
private observer;
|
|
64
|
+
private nextId;
|
|
65
|
+
constructor(capacity?: number);
|
|
66
|
+
/** Returns false when the browser cannot report event timing. */
|
|
67
|
+
start(): boolean;
|
|
68
|
+
stop(): void;
|
|
69
|
+
/** Is the automatic path available in this browser? */
|
|
70
|
+
get automatic(): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Time an interaction by hand.
|
|
73
|
+
*
|
|
74
|
+
* The automatic path depends on the Event Timing API, which Safari only
|
|
75
|
+
* gained in 16.4 and which does not fire for synthetic input at all — so
|
|
76
|
+
* anything driven by a test harness records nothing. This measures a specific
|
|
77
|
+
* action instead, up to the paint that follows it, and needs no browser
|
|
78
|
+
* support beyond `performance.now`.
|
|
79
|
+
*/
|
|
80
|
+
measure<T>(label: string, action: () => T): T;
|
|
81
|
+
/** Exposed for tests and for `measure`. */
|
|
82
|
+
record(timing: RawEventTiming): InteractionRecord;
|
|
83
|
+
clear(): void;
|
|
84
|
+
/**
|
|
85
|
+
* Joins render events to interactions by commit time. A render belongs to an
|
|
86
|
+
* interaction when it committed between the event starting and shortly after
|
|
87
|
+
* it finished — React commits just after the event handler returns.
|
|
88
|
+
*/
|
|
89
|
+
attribute(events: RenderEvent[]): InteractionRecord[];
|
|
90
|
+
}
|
|
91
|
+
declare function summarise(record: InteractionRecord): InteractionSummary;
|
|
92
|
+
declare function formatInteraction(summary: InteractionSummary): string;
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* "Where should I spend my next hour?"
|
|
96
|
+
*
|
|
97
|
+
* Render counts answer the wrong question — a component rendering 2 000 times
|
|
98
|
+
* for 0.01ms is not the problem, and one rendering 40 times for 12ms might be.
|
|
99
|
+
* This ranks by **estimated recoverable time**, so the top of the list is the
|
|
100
|
+
* biggest win rather than the noisiest component.
|
|
101
|
+
*/
|
|
102
|
+
interface Opportunity {
|
|
103
|
+
component: string;
|
|
104
|
+
source?: string;
|
|
105
|
+
/** Milliseconds plausibly recovered by fixing this. The ranking key. */
|
|
106
|
+
estimatedSavingMs: number;
|
|
107
|
+
/** Renders where no observable input changed. */
|
|
108
|
+
avoidableRenders: number;
|
|
109
|
+
/** Times the component was rebuilt rather than re-rendered. */
|
|
110
|
+
remounts: number;
|
|
111
|
+
averageSelfDuration: number;
|
|
112
|
+
/** One line: what to look at. Comes from the diagnostic engine, not from here. */
|
|
113
|
+
summary: string;
|
|
114
|
+
nextStep: string;
|
|
115
|
+
confidence: Confidence;
|
|
116
|
+
}
|
|
117
|
+
interface OpportunityInput {
|
|
118
|
+
events: RenderEvent[];
|
|
119
|
+
lifecycles: Map<string, {
|
|
120
|
+
remounts: number;
|
|
121
|
+
}>;
|
|
122
|
+
/** Ignore anything below this. Noise is worse than silence in a ranked list. */
|
|
123
|
+
minSavingMs?: number;
|
|
124
|
+
}
|
|
125
|
+
declare function rankOpportunities({ events, lifecycles, minSavingMs }: OpportunityInput): Opportunity[];
|
|
126
|
+
declare function formatOpportunities(opportunities: Opportunity[]): string;
|
|
127
|
+
|
|
5
128
|
interface TrackOptions {
|
|
6
129
|
/** Overrides the inferred component name. Required for anonymous components. */
|
|
7
130
|
name?: string;
|
|
@@ -155,6 +278,33 @@ declare function reset(): void;
|
|
|
155
278
|
declare function explain(componentName: string): string | undefined;
|
|
156
279
|
/** Structured form of `explain`, for building UIs on top. */
|
|
157
280
|
declare function explainStructured(componentName: string): Explanation | undefined;
|
|
281
|
+
/** Snapshot render behaviour for regression testing. See `react-render-detective/testing`. */
|
|
282
|
+
declare function getRenderProfile(scenario: string): RenderProfile;
|
|
283
|
+
/**
|
|
284
|
+
* Interactions, slowest first, with the renders that happened inside each.
|
|
285
|
+
*
|
|
286
|
+
* This is the bridge from render causality to what a user actually feels: the
|
|
287
|
+
* browser reports how long the interaction took, and the render events say
|
|
288
|
+
* which components spent that time and why.
|
|
289
|
+
*/
|
|
290
|
+
declare function getInteractions(): InteractionRecord[];
|
|
291
|
+
/** Structured analysis of one interaction. Defaults to the slowest recorded. */
|
|
292
|
+
declare function explainInteractionStructured(id?: string): InteractionSummary | undefined;
|
|
293
|
+
declare function explainInteraction(id?: string): string | undefined;
|
|
294
|
+
declare function printInteractions(limit?: number): void;
|
|
295
|
+
/**
|
|
296
|
+
* Time one interaction explicitly, up to the paint that follows it.
|
|
297
|
+
*
|
|
298
|
+
* Needed wherever the automatic path cannot see: Safari before 16.4, and any
|
|
299
|
+
* synthetic input, which never produces Event Timing entries.
|
|
300
|
+
*/
|
|
301
|
+
declare function measureInteraction<T>(label: string, action: () => T): T;
|
|
302
|
+
/**
|
|
303
|
+
* Components ranked by estimated recoverable time — the triage view. Render
|
|
304
|
+
* counts answer the wrong question; this answers "what should I fix first?".
|
|
305
|
+
*/
|
|
306
|
+
declare function getOpportunities(limit?: number): Opportunity[];
|
|
307
|
+
declare function printOpportunities(limit?: number): void;
|
|
158
308
|
/** Prints the application-level dashboard (§53). */
|
|
159
309
|
declare function printStats(): void;
|
|
160
310
|
/** Namespaced form, matching the documented `ReactRenderDetective.init()` usage. */
|
|
@@ -171,7 +321,15 @@ declare const ReactRenderDetective: {
|
|
|
171
321
|
reset: typeof reset;
|
|
172
322
|
explain: typeof explain;
|
|
173
323
|
explainStructured: typeof explainStructured;
|
|
324
|
+
getOpportunities: typeof getOpportunities;
|
|
325
|
+
printOpportunities: typeof printOpportunities;
|
|
326
|
+
getInteractions: typeof getInteractions;
|
|
327
|
+
explainInteraction: typeof explainInteraction;
|
|
328
|
+
explainInteractionStructured: typeof explainInteractionStructured;
|
|
329
|
+
printInteractions: typeof printInteractions;
|
|
330
|
+
measureInteraction: typeof measureInteraction;
|
|
331
|
+
getRenderProfile: typeof getRenderProfile;
|
|
174
332
|
printStats: typeof printStats;
|
|
175
333
|
};
|
|
176
334
|
|
|
177
|
-
export { AppStats, ComponentStats, Confidence, DetectiveConfig, DetectiveOptions, type Explanation, ReactRenderDetective, RenderDetective, type RenderDetectiveProps, RenderEvent, RenderReason, type TrackOptions, clear, configure, explain, explainEvents, explainStructured, formatExplanation, getComponentStats, getConfig, getEvents, getStats, init, isEnabled, printStats, reset, subscribe, useRenderDiagnostics, useTrackedContextValue, useTrackedEffect, useTrackedState, withRenderDetective };
|
|
335
|
+
export { AppStats, ComponentStats, Confidence, DetectiveConfig, DetectiveOptions, type Explanation, type InteractionRecord, type InteractionSummary, InteractionTracker, type Opportunity, ReactRenderDetective, RenderDetective, type RenderDetectiveProps, RenderEvent, RenderReason, type TrackOptions, clear, configure, explain, explainEvents, explainInteraction, explainInteractionStructured, explainStructured, formatExplanation, formatInteraction, formatOpportunities, getComponentStats, getConfig, getEvents, getInteractions, getOpportunities, getRenderProfile, getStats, init, isEnabled, measureInteraction, printInteractions, printOpportunities, printStats, rankOpportunities, reset, subscribe, summarise as summariseInteraction, useRenderDiagnostics, useTrackedContextValue, useTrackedEffect, useTrackedState, withRenderDetective };
|