react-render-detective 0.4.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-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 +154 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +126 -22
- package/dist/index.js.map +1 -1
- package/dist/overlay.cjs +2 -2
- package/dist/overlay.js +1 -1
- package/package.json +9 -4
- package/dist/chunk-DZ3BZ654.cjs.map +0 -1
- package/dist/chunk-QOGTEVBP.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var chunkJD4IJ4MN_cjs = require('./chunk-JD4IJ4MN.cjs');
|
|
4
|
-
var
|
|
4
|
+
var chunkOSPTERGK_cjs = require('./chunk-OSPTERGK.cjs');
|
|
5
5
|
var chunkH5RG2EPP_cjs = require('./chunk-H5RG2EPP.cjs');
|
|
6
6
|
var React = require('react');
|
|
7
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -26,6 +26,40 @@ function _interopNamespace(e) {
|
|
|
26
26
|
|
|
27
27
|
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
28
28
|
|
|
29
|
+
// src/console/style.ts
|
|
30
|
+
var PALETTE = {
|
|
31
|
+
plain: "",
|
|
32
|
+
dim: "color:#8a94a6",
|
|
33
|
+
strong: "font-weight:600",
|
|
34
|
+
good: "color:#1f9d5b",
|
|
35
|
+
warn: "color:#c2820a",
|
|
36
|
+
bad: "color:#d1493f;font-weight:600"
|
|
37
|
+
};
|
|
38
|
+
var supportsStyling = () => {
|
|
39
|
+
try {
|
|
40
|
+
return typeof window !== "undefined" && typeof document !== "undefined";
|
|
41
|
+
} catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
function styled(segments) {
|
|
46
|
+
if (!supportsStyling()) {
|
|
47
|
+
return [segments.map((s) => typeof s === "string" ? s : s[0]).join("")];
|
|
48
|
+
}
|
|
49
|
+
let format = "";
|
|
50
|
+
const styles = [];
|
|
51
|
+
for (const segment of segments) {
|
|
52
|
+
if (typeof segment === "string") {
|
|
53
|
+
format += segment.replace(/%/g, "%%");
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const [text, tone] = segment;
|
|
57
|
+
format += `%c${text.replace(/%/g, "%%")}%c`;
|
|
58
|
+
styles.push(PALETTE[tone], "");
|
|
59
|
+
}
|
|
60
|
+
return [format, ...styles];
|
|
61
|
+
}
|
|
62
|
+
|
|
29
63
|
// src/console/reporter.ts
|
|
30
64
|
var ICON = {
|
|
31
65
|
normal: "\xB7",
|
|
@@ -34,30 +68,102 @@ var ICON = {
|
|
|
34
68
|
"very-slow": "\u25B2\u25B2",
|
|
35
69
|
critical: "\u25A0"
|
|
36
70
|
};
|
|
71
|
+
var BATCH_WINDOW_MS = 400;
|
|
37
72
|
function attachConsoleReporter(detective) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
73
|
+
let pending = [];
|
|
74
|
+
let timer;
|
|
75
|
+
const flush = () => {
|
|
76
|
+
timer = void 0;
|
|
77
|
+
const batch = pending;
|
|
78
|
+
pending = [];
|
|
79
|
+
if (batch.length === 0) return;
|
|
41
80
|
try {
|
|
42
|
-
|
|
43
|
-
else printConcise(event, detective.config.slowRenderThreshold);
|
|
81
|
+
printBatch(batch, detective.config.slowRenderThreshold);
|
|
44
82
|
} catch {
|
|
45
83
|
}
|
|
84
|
+
};
|
|
85
|
+
const unsubscribe = detective.subscribe((event) => {
|
|
86
|
+
const mode = detective.config.mode;
|
|
87
|
+
if (mode === "silent") return;
|
|
88
|
+
if (mode === "verbose") {
|
|
89
|
+
try {
|
|
90
|
+
printVerbose(event);
|
|
91
|
+
} catch {
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
pending.push(event);
|
|
96
|
+
if (timer === void 0) {
|
|
97
|
+
timer = setTimeout(flush, BATCH_WINDOW_MS);
|
|
98
|
+
timer.unref?.();
|
|
99
|
+
}
|
|
46
100
|
});
|
|
101
|
+
return () => {
|
|
102
|
+
unsubscribe();
|
|
103
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
104
|
+
};
|
|
47
105
|
}
|
|
48
|
-
function
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
106
|
+
function printBatch(batch, slowThreshold) {
|
|
107
|
+
const byComponent = /* @__PURE__ */ new Map();
|
|
108
|
+
let totalMs = 0;
|
|
109
|
+
let avoidable = 0;
|
|
110
|
+
for (const event of batch) {
|
|
111
|
+
const key = event.component.name;
|
|
112
|
+
const entry = byComponent.get(key) ?? {
|
|
113
|
+
name: key,
|
|
114
|
+
source: event.component.source,
|
|
115
|
+
count: 0,
|
|
116
|
+
totalMs: 0,
|
|
117
|
+
reasons: /* @__PURE__ */ new Map(),
|
|
118
|
+
notableReasons: /* @__PURE__ */ new Map(),
|
|
119
|
+
avoidable: 0,
|
|
120
|
+
remount: false,
|
|
121
|
+
slow: false
|
|
122
|
+
};
|
|
123
|
+
entry.count++;
|
|
124
|
+
entry.totalMs += event.timings.selfDuration;
|
|
125
|
+
entry.reasons.set(event.diagnosis.reason, (entry.reasons.get(event.diagnosis.reason) ?? 0) + 1);
|
|
126
|
+
if (event.diagnosis.potentiallyAvoidable || event.timings.selfDuration >= slowThreshold) {
|
|
127
|
+
entry.notableReasons.set(event.diagnosis.reason, (entry.notableReasons.get(event.diagnosis.reason) ?? 0) + 1);
|
|
128
|
+
}
|
|
129
|
+
if (event.diagnosis.potentiallyAvoidable) entry.avoidable++;
|
|
130
|
+
if (event.diagnosis.summary.includes("rebuilt")) entry.remount = true;
|
|
131
|
+
if (event.timings.selfDuration >= slowThreshold) entry.slow = true;
|
|
132
|
+
if (!entry.worst || event.timings.selfDuration > entry.worst.timings.selfDuration) entry.worst = event;
|
|
133
|
+
byComponent.set(key, entry);
|
|
134
|
+
totalMs += event.timings.selfDuration;
|
|
135
|
+
if (event.diagnosis.potentiallyAvoidable) avoidable++;
|
|
136
|
+
}
|
|
137
|
+
const notable = [...byComponent.values()].filter((a) => a.avoidable > 0 || a.slow || a.remount);
|
|
138
|
+
if (notable.length === 0) return;
|
|
139
|
+
const ranked = [...notable].sort((a, b) => b.totalMs - a.totalMs);
|
|
140
|
+
const anySlow = ranked.some((a) => a.slow);
|
|
141
|
+
const segments = [
|
|
142
|
+
["[RRD] ", "dim"],
|
|
143
|
+
[`${batch.length} render${batch.length === 1 ? "" : "s"}`, "strong"],
|
|
144
|
+
[` \xB7 ${totalMs.toFixed(1)}ms`, "dim"]
|
|
145
|
+
];
|
|
146
|
+
if (avoidable > 0) segments.push([` \xB7 ${avoidable} potentially avoidable`, "warn"]);
|
|
147
|
+
for (const a of ranked.slice(0, 8)) {
|
|
148
|
+
const reasonSource = a.notableReasons.size > 0 ? a.notableReasons : a.reasons;
|
|
149
|
+
const reason = [...reasonSource.entries()].sort((x, y) => y[1] - x[1])[0]?.[0] ?? "unknown";
|
|
150
|
+
const tone = a.remount ? "bad" : a.slow ? "warn" : a.avoidable > 0 ? "warn" : "good";
|
|
151
|
+
const label2 = ` ${ICON[a.slow ? "slow" : "normal"]} ${a.name}${a.count > 1 ? ` \xD7${a.count}` : ""}`;
|
|
152
|
+
segments.push("\n", [label2.padEnd(30), tone], [`${a.totalMs.toFixed(1)}ms`, "plain"], [` ${reason}`, "dim"]);
|
|
153
|
+
if (a.remount) segments.push([" rebuilt", "bad"]);
|
|
154
|
+
if (a.avoidable > 0) segments.push([` ${a.avoidable} avoidable`, "warn"]);
|
|
155
|
+
if (a.source) segments.push(["\n " + a.source, "dim"]);
|
|
156
|
+
}
|
|
157
|
+
const worst = ranked[0]?.worst;
|
|
158
|
+
segments.push(
|
|
159
|
+
"\n",
|
|
160
|
+
[
|
|
161
|
+
worst?.diagnosis.suggestion ? ` \u2192 ${worst.diagnosis.suggestion}` : " \u2192 rrd.printOpportunities() to rank everything by recoverable time",
|
|
162
|
+
"dim"
|
|
163
|
+
]
|
|
164
|
+
);
|
|
165
|
+
const log = anySlow ? console.warn : console.log;
|
|
166
|
+
log(...styled(segments));
|
|
61
167
|
}
|
|
62
168
|
function printVerbose(event) {
|
|
63
169
|
const { diagnosis, timings } = event;
|
|
@@ -80,12 +186,10 @@ function printVerbose(event) {
|
|
|
80
186
|
for (const c of event.changedProps) console.log(propLine(c));
|
|
81
187
|
console.groupEnd();
|
|
82
188
|
}
|
|
83
|
-
if (event.unchangedProps.length > 0) {
|
|
84
|
-
console.log(`Props same: ${event.unchangedProps.join(", ")}`);
|
|
85
|
-
}
|
|
189
|
+
if (event.unchangedProps.length > 0) console.log(`Props same: ${event.unchangedProps.join(", ")}`);
|
|
86
190
|
if (event.trackedState.length > 0) {
|
|
87
191
|
console.log(
|
|
88
|
-
`State: ${event.trackedState.map((s) => `${s.name}: ${
|
|
192
|
+
`State: ${event.trackedState.map((s) => `${s.name}: ${chunkOSPTERGK_cjs.formatInspected(s.previous)} \u2192 ${chunkOSPTERGK_cjs.formatInspected(s.current)}`).join(", ")}`
|
|
89
193
|
);
|
|
90
194
|
}
|
|
91
195
|
if (event.contextChanges.length > 0) {
|
|
@@ -102,11 +206,11 @@ function printVerbose(event) {
|
|
|
102
206
|
}
|
|
103
207
|
function propLine(c) {
|
|
104
208
|
const head = `${c.key} (${c.valueType}) \u2014 ${describeKind(c)}`;
|
|
105
|
-
if (c.kind === "added") return `${head}: ${
|
|
106
|
-
if (c.kind === "removed") return `${head}: was ${
|
|
209
|
+
if (c.kind === "added") return `${head}: ${chunkOSPTERGK_cjs.formatInspected(c.current)}`;
|
|
210
|
+
if (c.kind === "removed") return `${head}: was ${chunkOSPTERGK_cjs.formatInspected(c.previous)}`;
|
|
107
211
|
return `${head}
|
|
108
|
-
previous: ${
|
|
109
|
-
current: ${
|
|
212
|
+
previous: ${chunkOSPTERGK_cjs.formatInspected(c.previous)}
|
|
213
|
+
current: ${chunkOSPTERGK_cjs.formatInspected(c.current)}`;
|
|
110
214
|
}
|
|
111
215
|
function describeKind(c) {
|
|
112
216
|
switch (c.kind) {
|
|
@@ -381,7 +485,7 @@ function formatOpportunities(opportunities) {
|
|
|
381
485
|
var AncestryContext = React.createContext(void 0);
|
|
382
486
|
AncestryContext.displayName = "RenderDetectiveAncestry";
|
|
383
487
|
function useInstrumentedNode(name, props, source) {
|
|
384
|
-
const detective =
|
|
488
|
+
const detective = chunkOSPTERGK_cjs.getDetective();
|
|
385
489
|
const parent = React.useContext(AncestryContext);
|
|
386
490
|
const [node] = React.useState(
|
|
387
491
|
() => detective.enabled ? detective.createNode(name, parent, source) : void 0
|
|
@@ -431,7 +535,7 @@ var IS_WRAPPER = /* @__PURE__ */ Symbol.for("react-render-detective.wrapper");
|
|
|
431
535
|
function withRenderDetective(Component, options = {}) {
|
|
432
536
|
if (Component[IS_WRAPPER]) return Component;
|
|
433
537
|
const name = options.name ?? componentName(Component);
|
|
434
|
-
|
|
538
|
+
chunkOSPTERGK_cjs.getDetective().noteDefinition(name, options.source, options.declaredInRender === true);
|
|
435
539
|
function RenderDetected(props) {
|
|
436
540
|
const { node, onRender } = useInstrumentedNode(name, props, options.source);
|
|
437
541
|
return renderInstrumented(node, onRender, /* @__PURE__ */ jsxRuntime.jsx(Component, { ...props }));
|
|
@@ -447,7 +551,7 @@ function RenderDetective({ name, children }) {
|
|
|
447
551
|
return renderInstrumented(node, onRender, children);
|
|
448
552
|
}
|
|
449
553
|
function useRenderDiagnostics(name, props) {
|
|
450
|
-
const detective =
|
|
554
|
+
const detective = chunkOSPTERGK_cjs.getDetective();
|
|
451
555
|
const parent = React.useContext(AncestryContext);
|
|
452
556
|
const [node] = React.useState(() => {
|
|
453
557
|
if (!detective.enabled) return void 0;
|
|
@@ -482,7 +586,7 @@ function useRenderDiagnostics(name, props) {
|
|
|
482
586
|
}
|
|
483
587
|
var useOwnerId = typeof React__namespace.useId === "function" ? React__namespace.useId : () => "";
|
|
484
588
|
function useTrackedState(name, initial) {
|
|
485
|
-
const detective =
|
|
589
|
+
const detective = chunkOSPTERGK_cjs.getDetective();
|
|
486
590
|
const node = React.useContext(AncestryContext);
|
|
487
591
|
const ownerId = useOwnerId();
|
|
488
592
|
const [state, setState] = React.useState(initial);
|
|
@@ -492,8 +596,8 @@ function useTrackedState(name, initial) {
|
|
|
492
596
|
if (node && owns && !Object.is(previous.current, state)) {
|
|
493
597
|
detective.recordStateChange(node, {
|
|
494
598
|
name,
|
|
495
|
-
previous:
|
|
496
|
-
current:
|
|
599
|
+
previous: chunkOSPTERGK_cjs.inspect(previous.current, detective.config.inspection),
|
|
600
|
+
current: chunkOSPTERGK_cjs.inspect(state, detective.config.inspection)
|
|
497
601
|
});
|
|
498
602
|
previous.current = state;
|
|
499
603
|
} else if (!owns) {
|
|
@@ -502,7 +606,7 @@ function useTrackedState(name, initial) {
|
|
|
502
606
|
return [state, setState];
|
|
503
607
|
}
|
|
504
608
|
function useTrackedEffect(name, effect, deps) {
|
|
505
|
-
const detective =
|
|
609
|
+
const detective = chunkOSPTERGK_cjs.getDetective();
|
|
506
610
|
const previous = React.useRef(void 0);
|
|
507
611
|
const changed = React.useRef([]);
|
|
508
612
|
if (detective.enabled) {
|
|
@@ -518,7 +622,7 @@ function useTrackedEffect(name, effect, deps) {
|
|
|
518
622
|
}, deps);
|
|
519
623
|
}
|
|
520
624
|
function useTrackedContextValue(contextName, value) {
|
|
521
|
-
const detective =
|
|
625
|
+
const detective = chunkOSPTERGK_cjs.getDetective();
|
|
522
626
|
const previous = React.useRef(void 0);
|
|
523
627
|
const first = React.useRef(true);
|
|
524
628
|
if (detective.enabled) {
|
|
@@ -526,8 +630,8 @@ function useTrackedContextValue(contextName, value) {
|
|
|
526
630
|
first.current = false;
|
|
527
631
|
} else if (!Object.is(previous.current, value)) {
|
|
528
632
|
const prev = previous.current;
|
|
529
|
-
const equal =
|
|
530
|
-
const changedKeys = isRecord(prev) && isRecord(value) ?
|
|
633
|
+
const equal = chunkOSPTERGK_cjs.shallowEqual(prev, value, detective.config);
|
|
634
|
+
const changedKeys = isRecord(prev) && isRecord(value) ? chunkOSPTERGK_cjs.diffProps(prev, value, detective.config).changed.map((c) => c.key) : [];
|
|
531
635
|
detective.recordContextChange({
|
|
532
636
|
contextName,
|
|
533
637
|
changedKeys,
|
|
@@ -552,7 +656,7 @@ function tracker() {
|
|
|
552
656
|
return g[INTERACTIONS];
|
|
553
657
|
}
|
|
554
658
|
function init(options = {}) {
|
|
555
|
-
const detective =
|
|
659
|
+
const detective = chunkOSPTERGK_cjs.getDetective();
|
|
556
660
|
detective.init(options);
|
|
557
661
|
const g = globalThis;
|
|
558
662
|
g[REPORTER]?.();
|
|
@@ -569,28 +673,28 @@ function init(options = {}) {
|
|
|
569
673
|
}
|
|
570
674
|
}
|
|
571
675
|
function configure(options) {
|
|
572
|
-
|
|
676
|
+
chunkOSPTERGK_cjs.getDetective().configure(options);
|
|
573
677
|
}
|
|
574
678
|
function getConfig() {
|
|
575
|
-
return
|
|
679
|
+
return chunkOSPTERGK_cjs.getDetective().config;
|
|
576
680
|
}
|
|
577
681
|
function isEnabled() {
|
|
578
|
-
return
|
|
682
|
+
return chunkOSPTERGK_cjs.getDetective().enabled;
|
|
579
683
|
}
|
|
580
684
|
function getEvents() {
|
|
581
|
-
return
|
|
685
|
+
return chunkOSPTERGK_cjs.getDetective().getEvents();
|
|
582
686
|
}
|
|
583
687
|
function getStats() {
|
|
584
|
-
return
|
|
688
|
+
return chunkOSPTERGK_cjs.getDetective().getStats();
|
|
585
689
|
}
|
|
586
690
|
function getComponentStats(name) {
|
|
587
|
-
return
|
|
691
|
+
return chunkOSPTERGK_cjs.getDetective().getComponentStats(name);
|
|
588
692
|
}
|
|
589
693
|
function subscribe(listener) {
|
|
590
|
-
return
|
|
694
|
+
return chunkOSPTERGK_cjs.getDetective().subscribe(listener);
|
|
591
695
|
}
|
|
592
696
|
function clear() {
|
|
593
|
-
|
|
697
|
+
chunkOSPTERGK_cjs.getDetective().clear();
|
|
594
698
|
tracker().clear();
|
|
595
699
|
}
|
|
596
700
|
function reset() {
|
|
@@ -599,18 +703,18 @@ function reset() {
|
|
|
599
703
|
g[REPORTER] = void 0;
|
|
600
704
|
g[INTERACTIONS]?.stop();
|
|
601
705
|
g[INTERACTIONS] = void 0;
|
|
602
|
-
|
|
706
|
+
chunkOSPTERGK_cjs.getDetective().reset();
|
|
603
707
|
}
|
|
604
708
|
function explain(componentName2) {
|
|
605
709
|
const explanation = explainStructured(componentName2);
|
|
606
710
|
return explanation ? chunkJD4IJ4MN_cjs.formatExplanation(explanation) : void 0;
|
|
607
711
|
}
|
|
608
712
|
function explainStructured(componentName2) {
|
|
609
|
-
return chunkJD4IJ4MN_cjs.explainEvents(componentName2, getEvents(),
|
|
713
|
+
return chunkJD4IJ4MN_cjs.explainEvents(componentName2, getEvents(), chunkOSPTERGK_cjs.getDetective().lifecycleOf(componentName2));
|
|
610
714
|
}
|
|
611
715
|
function getRenderProfile(scenario) {
|
|
612
716
|
const remounts = {};
|
|
613
|
-
for (const stats of
|
|
717
|
+
for (const stats of chunkOSPTERGK_cjs.getDetective().getComponentStats()) remounts[stats.name] = stats.remountCount;
|
|
614
718
|
return chunkH5RG2EPP_cjs.profileFromEvents(scenario, getEvents(), remounts);
|
|
615
719
|
}
|
|
616
720
|
function getInteractions() {
|
|
@@ -639,7 +743,7 @@ function measureInteraction(label2, action) {
|
|
|
639
743
|
return tracker().measure(label2, action);
|
|
640
744
|
}
|
|
641
745
|
function getOpportunities(limit = 10) {
|
|
642
|
-
const detective =
|
|
746
|
+
const detective = chunkOSPTERGK_cjs.getDetective();
|
|
643
747
|
const lifecycles = /* @__PURE__ */ new Map();
|
|
644
748
|
for (const stats of detective.getComponentStats()) {
|
|
645
749
|
lifecycles.set(stats.name, { remounts: stats.remountCount });
|