Skip to content

Commit b5b2efc

Browse files
authored
Merge branch 'main' into feat/select
2 parents 5fc2ecd + 97f7327 commit b5b2efc

File tree

11 files changed

+175
-144
lines changed

11 files changed

+175
-144
lines changed

README.md

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,6 @@ import React from 'react';
121121
scan({
122122
enabled: true,
123123
log: true, // logs render info to console (default: false)
124-
clearLog: false, // clears the console per group of renders (default: false)
125124
});
126125
```
127126

@@ -169,19 +168,19 @@ scan({
169168
* Long task threshold in milliseconds, only show
170169
* when main thread is blocked for longer than this
171170
*/
172-
longTaskThreshold: 50;
171+
longTaskThreshold: 50,
173172

174173
/**
175-
* Clear aggregated fibers after this time in milliseconds
174+
* Report data to getReport()
176175
*/
177-
resetCountTimeout: 5000;
178-
179-
onCommitStart?: () => void;
180-
onRender?: (fiber, render) => void;
181-
onCommitFinish?: () => void;
182-
onPaintStart?: (outline) => void;
183-
onPaintFinish?: (outline) => void;
184-
})
176+
report: false,
177+
178+
onCommitStart: () => {},
179+
onRender: (fiber, render) => {},
180+
onCommitFinish: () => {},
181+
onPaintStart: (outline) => {},
182+
onPaintFinish: (outline) => {},
183+
});
185184
```
186185

187186
</details>
@@ -232,19 +231,19 @@ withScan(Component, {
232231
* Long task threshold in milliseconds, only show
233232
* when main thread is blocked for longer than this
234233
*/
235-
longTaskThreshold: 50;
234+
longTaskThreshold: 50,
236235

237236
/**
238-
* Clear aggregated fibers after this time in milliseconds
237+
* Report data to getReport()
239238
*/
240-
resetCountTimeout: 5000;
241-
242-
onCommitStart?: () => void;
243-
onRender?: (fiber, render) => void;
244-
onCommitFinish?: () => void;
245-
onPaintStart?: (outline) => void;
246-
onPaintFinish?: (outline) => void;
247-
})
239+
report: false,
240+
241+
onCommitStart: () => {},
242+
onRender: (fiber, render) => {},
243+
onCommitFinish: () => {},
244+
onPaintStart: (outline) => {},
245+
onPaintFinish: (outline) => {},
246+
});
248247
```
249248

250249
</details>
@@ -257,6 +256,8 @@ withScan(Component, {
257256
Get a aggregated report of all components and renders.
258257

259258
```jsx
259+
scan({ report: true });
260+
260261
const report = getReport();
261262

262263
for (const component in report) {
@@ -310,19 +311,19 @@ setOptions({
310311
* Long task threshold in milliseconds, only show
311312
* when main thread is blocked for longer than this
312313
*/
313-
longTaskThreshold: 50;
314+
longTaskThreshold: 50,
314315

315316
/**
316-
* Clear aggregated fibers after this time in milliseconds
317+
* Report data to getReport()
317318
*/
318-
resetCountTimeout: 5000;
319-
320-
onCommitStart?: () => void;
321-
onRender?: (fiber, render) => void;
322-
onCommitFinish?: () => void;
323-
onPaintStart?: (outline) => void;
324-
onPaintFinish?: (outline) => void;
325-
})
319+
report: false,
320+
321+
onCommitStart: () => {},
322+
onRender: (fiber, render) => {},
323+
onCommitFinish: () => {},
324+
onPaintStart: (outline) => {},
325+
onPaintFinish: (outline) => {},
326+
});
326327
```
327328

328329
</details>
@@ -416,12 +417,20 @@ We expect all contributors to abide by the terms of our [Code of Conduct](https:
416417
- [x] Don't show label if no reconciliation occurred ("client renders" in DevTools)
417418
- [x] "global" counter using `sessionStorage`, aggregate count stats instead of immediate replacement
418419
- [x] Give a general report of the app's performance
419-
420+
- [ ] checkbox filtering API, leaderboard
421+
- [ ] Offscreen canvas on worker thread
422+
- [x] heatmap decay (stacked renders will be more intense)
423+
- [ ] Investigate components (UI allowlist)
424+
- [ ] UI for turning on/off options
425+
- [ ] “PageSpeed insights” for React
420426
- [ ] React Native support
421427
- [ ] Name / explain the actual problem, docs
422428
- [ ] Simple FPS counter
423429
- [ ] Drag and select areas of the screen to scan
424430
- [ ] Long task progress bar filter
431+
- [x] Report should include all renders
432+
- [ ] [Runtime version guarding](https://github.com/lahmatiy/react-render-tracker/blob/229ad0e9c28853615300724d5dc86c140f250f60/src/publisher/react-integration/utils/getInternalReactConstants.ts#L28)
433+
- [ ] React as peer dependency (lock version to range)
425434
- [ ] Add a funny mascot, like the ["Stop I'm Changing" dude](https://www.youtube.com/shorts/FwOZdX7bDKI?app=desktop)
426435

427436
## Acknowledgments

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-scan",
3-
"version": "0.0.9",
3+
"version": "0.0.10",
44
"description": "Scan your React app for renders",
55
"keywords": [
66
"react",
@@ -23,7 +23,6 @@
2323
"email": "[email protected]",
2424
"url": "https://million.dev"
2525
},
26-
"sideEffects": false,
2726
"type": "commonjs",
2827
"exports": {
2928
"./package.json": "./package.json",

src/core/index.ts

Lines changed: 28 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,20 @@ interface Options {
7070
*/
7171
resetCountTimeout?: number;
7272

73+
/**
74+
* Maximum number of renders for red indicator
75+
*
76+
* @default 20
77+
*/
78+
maxRenders?: number;
79+
80+
/**
81+
* Report data to getReport()
82+
*
83+
* @default false
84+
*/
85+
report?: boolean;
86+
7387
onCommitStart?: () => void;
7488
onRender?: (fiber: Fiber, render: Render) => void;
7589
onCommitFinish?: () => void;
@@ -92,14 +106,7 @@ interface Internals {
92106
{
93107
count: number;
94108
time: number;
95-
}
96-
>;
97-
fiberMap: WeakMap<
98-
Fiber,
99-
{
100-
count: number;
101-
time: number;
102-
lastUpdated: number;
109+
renders: Render[];
103110
}
104111
>;
105112
}
@@ -126,17 +133,9 @@ export const ReactScanInternals: Internals = {
126133
log: false,
127134
showToolbar: true,
128135
longTaskThreshold: 50,
129-
resetCountTimeout: 5000,
136+
report: false,
130137
},
131138
reportData: {},
132-
fiberMap: new WeakMap<
133-
Fiber,
134-
{
135-
count: number;
136-
time: number;
137-
lastUpdated: number;
138-
}
139-
>(),
140139
scheduledOutlines: [],
141140
activeOutlines: [],
142141
};
@@ -182,15 +181,16 @@ export const start = () => {
182181
onRender(fiber, render) {
183182
options.onRender?.(fiber, render);
184183
const outline = getOutline(fiber, render);
185-
if (outline) {
186-
if (
187-
render.name &&
188-
ReactScanInternals.componentNameAllowList.size > 0 &&
189-
!ReactScanInternals.componentNameAllowList.has(render.name)
190-
) {
191-
/** */
192-
} else ReactScanInternals.scheduledOutlines.push(outline);
193-
}
184+
if (!outline) return;
185+
const { componentNameAllowList } = ReactScanInternals;
186+
if (
187+
!render.name ||
188+
!componentNameAllowList.size ||
189+
componentNameAllowList.has(render.name)
190+
) {
191+
ReactScanInternals.scheduledOutlines.push(outline);
192+
}
193+
194194

195195
if (options.playSound && audioContext) {
196196
const renderTimeThreshold = 10;
@@ -203,40 +203,17 @@ export const start = () => {
203203

204204
if (render.name) {
205205
const prev = ReactScanInternals.reportData[render.name];
206+
prev.renders.push(render);
206207
ReactScanInternals.reportData[render.name] = {
207208
count: (prev?.count ?? 0) + render.count,
208209
time: (prev?.time ?? 0) + render.time,
210+
renders: prev.renders,
209211
};
210212
renderCheckbox();
211213
}
212214

213215
requestAnimationFrame(() => {
214216
flushOutlines(ctx, new Map(), toolbar, perfObserver);
215-
216-
const fiberData = ReactScanInternals.fiberMap.get(fiber);
217-
const now = Date.now();
218-
let count = render.count;
219-
let time = render.time;
220-
if (fiberData) {
221-
// clear aggregated fibers after 5 seconds
222-
if (
223-
now - fiberData.lastUpdated >
224-
(options.resetCountTimeout ?? 5000)
225-
) {
226-
ReactScanInternals.fiberMap.delete(fiber);
227-
} else {
228-
count += fiberData.count;
229-
time += fiberData.time;
230-
render.count = count;
231-
render.time = time;
232-
}
233-
}
234-
235-
ReactScanInternals.fiberMap.set(fiber, {
236-
count,
237-
time,
238-
lastUpdated: now,
239-
});
240217
});
241218
},
242219
onCommitFinish() {

src/core/instrumentation/fiber.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ export const didFiberRender = (fiber: Fiber): boolean => {
128128

129129
const prevProps = fiber.alternate?.memoizedProps || {};
130130
const flags = fiber.flags ?? (fiber as any).effectTag ?? 0;
131-
const subtreeFlags = fiber.subtreeFlags ?? 0;
132131

133132
switch (fiber.tag) {
134133
case ClassComponentTag:
@@ -137,10 +136,7 @@ export const didFiberRender = (fiber: Fiber): boolean => {
137136
case ForwardRefTag:
138137
case MemoComponentTag:
139138
case SimpleMemoComponentTag:
140-
return (
141-
(flags & PerformedWorkFlag) === PerformedWorkFlag &&
142-
(subtreeFlags & PerformedWorkFlag) === PerformedWorkFlag
143-
);
139+
return (flags & PerformedWorkFlag) === PerformedWorkFlag;
144140
default:
145141
// Host nodes (DOM, root, etc.)
146142
if (!fiber.alternate) return true;

src/core/utils.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const getLabelText = (renders: Render[]) => {
3737
([, a], [, b]) => b.count - a.count,
3838
);
3939

40+
const parts: string[] = [];
4041
for (const [name, { count, trigger, forget }] of sortedComponents) {
4142
let text = name;
4243
if (count > 1) {
@@ -48,9 +49,11 @@ export const getLabelText = (renders: Render[]) => {
4849
if (forget) {
4950
text = `${text} ✨`;
5051
}
51-
labelText += text;
52+
parts.push(text);
5253
}
5354

55+
labelText = parts.join(' ');
56+
5457
if (!labelText.length) return null;
5558
if (labelText.length > 20) {
5659
labelText = `${labelText.slice(0, 20)}…`;

src/core/web/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@ export const createOverlay = () => {
1313
const dpi = window.devicePixelRatio;
1414
canvas.width = dpi * window.innerWidth;
1515
canvas.height = dpi * window.innerHeight;
16-
ctx?.scale(dpi, dpi);
16+
17+
if (ctx) {
18+
ctx.resetTransform();
19+
ctx.scale(dpi, dpi);
20+
}
21+
1722
resizeScheduled = false;
1823
};
1924

0 commit comments

Comments
 (0)