Skip to content

Commit e77959a

Browse files
authored
feat: notifications (#299)
1 parent 67a4110 commit e77959a

35 files changed

+6893
-193
lines changed

biome.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@
2020
]
2121
},
2222
"organizeImports": {
23-
"enabled": true
23+
"enabled": false
2424
},
2525
"linter": {
2626
"enabled": true,
2727
"rules": {
28-
"recommended": true,
28+
"recommended": false,
2929
"correctness": {
3030
"noUnusedFunctionParameters": {
3131
"level": "warn",

packages/scan/package.json

Lines changed: 10 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
{
22
"name": "react-scan",
3-
"version": "0.1.3",
3+
"version": "0.2.8",
44
"description": "Scan your React app for renders",
5-
"keywords": [
6-
"react",
7-
"react-scan",
8-
"react scan",
9-
"render",
10-
"performance"
11-
],
5+
"keywords": ["react", "react-scan", "react scan", "render", "performance"],
126
"homepage": "https://react-scan.million.dev",
137
"bugs": {
148
"url": "https://github.com/aidenybai/react-scan/issues"
@@ -172,27 +166,17 @@
172166
"types": "dist/index.d.ts",
173167
"typesVersions": {
174168
"*": {
175-
"monitoring": [
176-
"./dist/core/monitor/index.d.ts"
177-
],
178-
"monitoring/next": [
179-
"./dist/core/monitor/params/next.d.ts"
180-
],
169+
"monitoring": ["./dist/core/monitor/index.d.ts"],
170+
"monitoring/next": ["./dist/core/monitor/params/next.d.ts"],
181171
"monitoring/react-router-legacy": [
182172
"./dist/core/monitor/params/react-router-v5.d.ts"
183173
],
184174
"monitoring/react-router": [
185175
"./dist/core/monitor/params/react-router-v6.d.ts"
186176
],
187-
"monitoring/remix": [
188-
"./dist/core/monitor/params/remix.d.ts"
189-
],
190-
"monitoring/astro": [
191-
"./dist/core/monitor/params/astro/index.ts"
192-
],
193-
"react-component-name/vite": [
194-
"./dist/react-component-name/vite.d.ts"
195-
],
177+
"monitoring/remix": ["./dist/core/monitor/params/remix.d.ts"],
178+
"monitoring/astro": ["./dist/core/monitor/params/astro/index.ts"],
179+
"react-component-name/vite": ["./dist/react-component-name/vite.d.ts"],
196180
"react-component-name/webpack": [
197181
"./dist/react-component-name/webpack.d.ts"
198182
],
@@ -208,23 +192,12 @@
208192
"react-component-name/rollup": [
209193
"./dist/react-component-name/rollup.d.ts"
210194
],
211-
"react-component-name/astro": [
212-
"./dist/react-component-name/astro.d.ts"
213-
],
214-
"react-component-name/loader": [
215-
"./dist/react-component-name/loader.d.ts"
216-
]
195+
"react-component-name/astro": ["./dist/react-component-name/astro.d.ts"],
196+
"react-component-name/loader": ["./dist/react-component-name/loader.d.ts"]
217197
}
218198
},
219199
"bin": "bin/cli.js",
220-
"files": [
221-
"dist",
222-
"bin",
223-
"package.json",
224-
"README.md",
225-
"LICENSE",
226-
"auto.d.ts"
227-
],
200+
"files": ["dist", "bin", "package.json", "README.md", "LICENSE", "auto.d.ts"],
228201
"scripts": {
229202
"dev:kitchen": "node dist/cli.js http://localhost:5173",
230203
"build": "npm run build:css && NODE_ENV=production tsup",

packages/scan/src/core/index.ts

Lines changed: 82 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import type {
2424
} from './instrumentation';
2525
import type { InternalInteraction } from './monitor/types';
2626
import type { getSession } from './monitor/utils';
27+
import { startTimingTracking } from './notifications/event-tracking';
28+
import { createHighlightCanvas } from './notifications/outline-overlay';
2729

2830
let rootContainer: HTMLDivElement | null = null;
2931
let shadowRoot: ShadowRoot | null = null;
@@ -160,6 +162,22 @@ export interface Options {
160162
*/
161163
trackUnnecessaryRenders?: boolean;
162164

165+
/**
166+
* Should the FPS meter show in the toolbar
167+
*
168+
* @default true
169+
*/
170+
showFPS?: boolean;
171+
172+
/**
173+
* Should react scan log internal errors to the console.
174+
*
175+
* Useful if react scan is not behaving expected and you want to provide information to maintainers when submitting an issue https://github.com/aidenybai/react-scan/issues
176+
*
177+
* @default false
178+
*/
179+
_debug?: 'verbose' | false;
180+
163181
onCommitStart?: () => void;
164182
onRender?: (fiber: Fiber, renders: Array<Render>) => void;
165183
onCommitFinish?: () => void;
@@ -197,6 +215,9 @@ export interface StoreType {
197215
fiberRoots: WeakSet<Fiber>;
198216
reportData: Map<number, RenderData>;
199217
legacyReportData: Map<string, RenderData>;
218+
interactionListeningForRenders:
219+
| ((fiber: Fiber, renders: Array<Render>) => void)
220+
| null;
200221
}
201222

202223
export type OutlineKey = `${string}-${string}`;
@@ -270,6 +291,7 @@ export const Store: StoreType = {
270291
reportData: new Map<number, RenderData>(),
271292
legacyReportData: new Map<string, RenderData>(),
272293
lastReportTime: signal(0),
294+
interactionListeningForRenders: null,
273295
};
274296

275297
export const ReactScanInternals: Internals = {
@@ -286,6 +308,7 @@ export const ReactScanInternals: Internals = {
286308
// alwaysShowLabels: false,
287309
animationSpeed: 'fast',
288310
dangerouslyForceRunInProduction: false,
311+
showFPS: true,
289312
// smoothlyAnimateOutlines: true,
290313
// trackUnnecessaryRenders: false,
291314
}),
@@ -465,50 +488,62 @@ export const getIsProduction = () => {
465488
};
466489

467490
export const start = () => {
468-
if (typeof window === 'undefined') {
469-
return;
470-
}
491+
try {
492+
if (typeof window === 'undefined') {
493+
return;
494+
}
471495

472-
if (
473-
getIsProduction() &&
474-
!ReactScanInternals.options.value.dangerouslyForceRunInProduction
475-
) {
476-
return;
477-
}
496+
if (
497+
getIsProduction() &&
498+
!ReactScanInternals.options.value.dangerouslyForceRunInProduction
499+
) {
500+
return;
501+
}
478502

479-
const localStorageOptions =
480-
readLocalStorage<LocalStorageOptions>('react-scan-options');
503+
const localStorageOptions =
504+
readLocalStorage<LocalStorageOptions>('react-scan-options');
481505

482-
if (localStorageOptions) {
483-
const validLocalOptions = validateOptions(localStorageOptions);
506+
if (localStorageOptions) {
507+
const validLocalOptions = validateOptions(localStorageOptions);
484508

485-
if (Object.keys(validLocalOptions).length > 0) {
486-
ReactScanInternals.options.value = {
487-
...ReactScanInternals.options.value,
488-
...validLocalOptions,
489-
};
509+
if (Object.keys(validLocalOptions).length > 0) {
510+
ReactScanInternals.options.value = {
511+
...ReactScanInternals.options.value,
512+
...validLocalOptions,
513+
};
514+
}
490515
}
491-
}
492516

493-
const options = getOptions();
494-
495-
initReactScanInstrumentation(() => {
496-
initToolbar(!!options.value.showToolbar);
497-
});
498-
499-
const isUsedInBrowserExtension = typeof window !== 'undefined';
500-
if (!Store.monitor.value && !isUsedInBrowserExtension) {
501-
setTimeout(() => {
502-
if (isInstrumentationActive()) return;
503-
// biome-ignore lint/suspicious/noConsole: Intended debug output
517+
const options = getOptions();
518+
519+
initReactScanInstrumentation(() => {
520+
initToolbar(!!options.value.showToolbar);
521+
});
522+
523+
const isUsedInBrowserExtension = typeof window !== 'undefined';
524+
if (!Store.monitor.value && !isUsedInBrowserExtension) {
525+
setTimeout(() => {
526+
if (isInstrumentationActive()) return;
527+
// biome-ignore lint/suspicious/noConsole: Intended debug output
528+
console.error(
529+
'[React Scan] Failed to load. Must import React Scan before React runs.',
530+
);
531+
}, 5000);
532+
}
533+
} catch (e) {
534+
if (ReactScanInternals.options.value._debug === 'verbose') {
504535
console.error(
505-
'[React Scan] Failed to load. Must import React Scan before React runs.',
536+
'[React Scan Internal Error]',
537+
'Failed to create notifications outline canvas',
538+
e,
506539
);
507-
}, 5000);
540+
}
508541
}
509542
};
510543

511544
const initToolbar = (showToolbar: boolean) => {
545+
startTimingTracking();
546+
createNotificationsOutlineCanvas();
512547
const windowToolbarContainer = window.__REACT_SCAN_TOOLBAR_CONTAINER__;
513548

514549
if (!showToolbar) {
@@ -521,6 +556,21 @@ const initToolbar = (showToolbar: boolean) => {
521556
createToolbar(shadowRoot);
522557
};
523558

559+
const createNotificationsOutlineCanvas = () => {
560+
try {
561+
const highlightRoot = document.documentElement;
562+
createHighlightCanvas(highlightRoot);
563+
} catch (e) {
564+
if (ReactScanInternals.options.value._debug === 'verbose') {
565+
console.error(
566+
'[React Scan Internal Error]',
567+
'Failed to create notifications outline canvas',
568+
e,
569+
);
570+
}
571+
}
572+
};
573+
524574
export const scan = (options: Options = {}) => {
525575
setOptions(options);
526576
const isInIframe = Store.isInIframe.value;

packages/scan/src/core/monitor/utils.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,19 @@ export const getSession = async ({
131131
cachedSession = session;
132132
return session;
133133
};
134+
135+
136+
137+
export const not_globally_unique_generateId = () => {
138+
if (typeof window === 'undefined') {
139+
return '0';
140+
}
141+
142+
// @ts-expect-error
143+
if (window.reactScanIdCounter === undefined) {
144+
// @ts-expect-error
145+
window.reactScanIdCounter = 0;
146+
}
147+
// @ts-expect-error
148+
return `${++window.reactScanIdCounter}`;
149+
};

0 commit comments

Comments
 (0)