@presto1314w/vite-devtools-browser 0.3.3 → 0.3.5
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/LICENSE +21 -21
- package/README.md +135 -322
- package/dist/browser-session.d.ts +11 -1
- package/dist/browser-session.js +29 -40
- package/dist/cli.js +57 -57
- package/dist/client.js +2 -2
- package/dist/daemon.js +3 -8
- package/dist/event-queue.d.ts +10 -1
- package/dist/event-queue.js +52 -2
- package/dist/paths.d.ts +25 -0
- package/dist/paths.js +42 -4
- package/dist/react/hook-manager.d.ts +29 -0
- package/dist/react/hook-manager.js +75 -0
- package/dist/react/hook.d.ts +1 -0
- package/dist/react/hook.js +227 -0
- package/dist/react/profiler.d.ts +55 -0
- package/dist/react/profiler.js +166 -0
- package/dist/react/zustand.d.ts +31 -0
- package/dist/react/zustand.js +113 -0
- package/dist/vue/devtools.d.ts +1 -1
- package/dist/vue/devtools.js +41 -3
- package/package.json +21 -15
package/dist/cli.js
CHANGED
|
@@ -205,63 +205,63 @@ export function exit(io, res, msg) {
|
|
|
205
205
|
io.exit(0);
|
|
206
206
|
}
|
|
207
207
|
export function printUsage() {
|
|
208
|
-
return `
|
|
209
|
-
vite-browser - Programmatic access to Vue/React/Svelte DevTools and Vite dev server
|
|
210
|
-
|
|
211
|
-
USAGE
|
|
212
|
-
vite-browser <command> [options]
|
|
213
|
-
|
|
214
|
-
BROWSER CONTROL
|
|
215
|
-
open <url> [--cookies-json <file>] Launch browser and navigate
|
|
216
|
-
close Close browser and daemon
|
|
217
|
-
goto <url> Full-page navigation
|
|
218
|
-
back Go back in history
|
|
219
|
-
reload Reload current page
|
|
220
|
-
|
|
221
|
-
FRAMEWORK DETECTION
|
|
222
|
-
detect Detect framework (vue/react/svelte)
|
|
223
|
-
|
|
224
|
-
VUE COMMANDS
|
|
225
|
-
vue tree [id] Show Vue component tree or inspect component
|
|
226
|
-
vue pinia [store] Show Pinia stores or inspect specific store
|
|
227
|
-
vue router Show Vue Router information
|
|
228
|
-
|
|
229
|
-
REACT COMMANDS
|
|
230
|
-
react tree [id] Show React component tree or inspect component
|
|
231
|
-
|
|
232
|
-
SVELTE COMMANDS
|
|
233
|
-
svelte tree [id] Show Svelte component tree or inspect component
|
|
234
|
-
|
|
235
|
-
VITE COMMANDS
|
|
236
|
-
vite restart Restart Vite dev server
|
|
237
|
-
vite hmr Show HMR summary
|
|
238
|
-
vite hmr trace [--limit <n>] Show HMR timeline
|
|
239
|
-
vite hmr clear Clear tracked HMR timeline
|
|
240
|
-
vite runtime Show Vite runtime status
|
|
241
|
-
vite module-graph [--filter <txt>] [--limit <n>]
|
|
242
|
-
Show loaded Vite module resources
|
|
243
|
-
vite module-graph trace [--filter <txt>] [--limit <n>]
|
|
244
|
-
Show module additions/removals since baseline
|
|
245
|
-
vite module-graph clear Clear module-graph baseline
|
|
246
|
-
errors Show build/runtime errors
|
|
247
|
-
errors --mapped Show errors with source-map mapping
|
|
248
|
-
errors --mapped --inline-source Include mapped source snippets
|
|
249
|
-
correlate errors [--window <ms>] Correlate current errors with recent HMR events
|
|
250
|
-
correlate renders [--window <ms>] Summarize recent render/update propagation evidence
|
|
251
|
-
correlate errors --mapped Correlate mapped errors with recent HMR events
|
|
252
|
-
diagnose hmr [--window <ms>] Diagnose HMR failures from runtime, errors, and trace data
|
|
253
|
-
diagnose hmr [--limit <n>] Control how many recent HMR trace entries are inspected
|
|
254
|
-
diagnose propagation [--window <ms>]
|
|
255
|
-
Diagnose likely update -> render -> error propagation
|
|
256
|
-
logs Show dev server logs
|
|
257
|
-
|
|
258
|
-
UTILITIES
|
|
259
|
-
screenshot Save screenshot to temp file
|
|
260
|
-
eval <script> Evaluate JavaScript in page context
|
|
261
|
-
network [idx] List network requests or inspect one
|
|
262
|
-
|
|
263
|
-
OPTIONS
|
|
264
|
-
-h, --help Show this help message
|
|
208
|
+
return `
|
|
209
|
+
vite-browser - Programmatic access to Vue/React/Svelte DevTools and Vite dev server
|
|
210
|
+
|
|
211
|
+
USAGE
|
|
212
|
+
vite-browser <command> [options]
|
|
213
|
+
|
|
214
|
+
BROWSER CONTROL
|
|
215
|
+
open <url> [--cookies-json <file>] Launch browser and navigate
|
|
216
|
+
close Close browser and daemon
|
|
217
|
+
goto <url> Full-page navigation
|
|
218
|
+
back Go back in history
|
|
219
|
+
reload Reload current page
|
|
220
|
+
|
|
221
|
+
FRAMEWORK DETECTION
|
|
222
|
+
detect Detect framework (vue/react/svelte)
|
|
223
|
+
|
|
224
|
+
VUE COMMANDS
|
|
225
|
+
vue tree [id] Show Vue component tree or inspect component
|
|
226
|
+
vue pinia [store] Show Pinia stores or inspect specific store
|
|
227
|
+
vue router Show Vue Router information
|
|
228
|
+
|
|
229
|
+
REACT COMMANDS
|
|
230
|
+
react tree [id] Show React component tree or inspect component
|
|
231
|
+
|
|
232
|
+
SVELTE COMMANDS
|
|
233
|
+
svelte tree [id] Show Svelte component tree or inspect component
|
|
234
|
+
|
|
235
|
+
VITE COMMANDS
|
|
236
|
+
vite restart Restart Vite dev server
|
|
237
|
+
vite hmr Show HMR summary
|
|
238
|
+
vite hmr trace [--limit <n>] Show HMR timeline
|
|
239
|
+
vite hmr clear Clear tracked HMR timeline
|
|
240
|
+
vite runtime Show Vite runtime status
|
|
241
|
+
vite module-graph [--filter <txt>] [--limit <n>]
|
|
242
|
+
Show loaded Vite module resources
|
|
243
|
+
vite module-graph trace [--filter <txt>] [--limit <n>]
|
|
244
|
+
Show module additions/removals since baseline
|
|
245
|
+
vite module-graph clear Clear module-graph baseline
|
|
246
|
+
errors Show build/runtime errors
|
|
247
|
+
errors --mapped Show errors with source-map mapping
|
|
248
|
+
errors --mapped --inline-source Include mapped source snippets
|
|
249
|
+
correlate errors [--window <ms>] Correlate current errors with recent HMR events
|
|
250
|
+
correlate renders [--window <ms>] Summarize recent render/update propagation evidence
|
|
251
|
+
correlate errors --mapped Correlate mapped errors with recent HMR events
|
|
252
|
+
diagnose hmr [--window <ms>] Diagnose HMR failures from runtime, errors, and trace data
|
|
253
|
+
diagnose hmr [--limit <n>] Control how many recent HMR trace entries are inspected
|
|
254
|
+
diagnose propagation [--window <ms>]
|
|
255
|
+
Diagnose likely update -> render -> error propagation
|
|
256
|
+
logs Show dev server logs
|
|
257
|
+
|
|
258
|
+
UTILITIES
|
|
259
|
+
screenshot Save screenshot to temp file
|
|
260
|
+
eval <script> Evaluate JavaScript in page context
|
|
261
|
+
network [idx] List network requests or inspect one
|
|
262
|
+
|
|
263
|
+
OPTIONS
|
|
264
|
+
-h, --help Show this help message
|
|
265
265
|
`;
|
|
266
266
|
}
|
|
267
267
|
function isEntrypoint(argv1) {
|
package/dist/client.js
CHANGED
|
@@ -3,7 +3,7 @@ import { readFileSync, existsSync, rmSync } from "node:fs";
|
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { socketPath, pidFile } from "./paths.js";
|
|
6
|
+
import { socketPath, pidFile, isWindows } from "./paths.js";
|
|
7
7
|
export function createClientDeps() {
|
|
8
8
|
const ext = import.meta.url.endsWith(".ts") ? ".ts" : ".js";
|
|
9
9
|
const daemonPath = fileURLToPath(new URL(`./daemon${ext}`, import.meta.url));
|
|
@@ -86,7 +86,7 @@ export function no() {
|
|
|
86
86
|
return false;
|
|
87
87
|
}
|
|
88
88
|
export function removeSocketFile(path, removeFile = rmSync) {
|
|
89
|
-
if (
|
|
89
|
+
if (isWindows)
|
|
90
90
|
return;
|
|
91
91
|
removeFile(path, { force: true });
|
|
92
92
|
}
|
package/dist/daemon.js
CHANGED
|
@@ -8,6 +8,7 @@ import { diagnoseHMR, formatDiagnosisReport } from "./diagnose.js";
|
|
|
8
8
|
import { diagnosePropagation, formatPropagationDiagnosisReport } from "./diagnose-propagation.js";
|
|
9
9
|
import { extractModules } from "./event-analysis.js";
|
|
10
10
|
import { socketDir, socketPath, pidFile } from "./paths.js";
|
|
11
|
+
import { removeSocketFile } from "./client.js";
|
|
11
12
|
import { correlateRenderPropagation, formatPropagationTraceReport } from "./trace.js";
|
|
12
13
|
import { EventQueue } from "./event-queue.js";
|
|
13
14
|
import * as networkLog from "./network.js";
|
|
@@ -303,7 +304,7 @@ export function startDaemon() {
|
|
|
303
304
|
networkLog.setEventQueue(eventQueue);
|
|
304
305
|
const run = createRunner();
|
|
305
306
|
mkdirSync(socketDir, { recursive: true, mode: 0o700 });
|
|
306
|
-
removeSocketFile();
|
|
307
|
+
removeSocketFile(socketPath);
|
|
307
308
|
rmSync(pidFile, { force: true });
|
|
308
309
|
writeFileSync(pidFile, String(process.pid));
|
|
309
310
|
const server = createServer((socket) => {
|
|
@@ -330,16 +331,10 @@ export function startDaemon() {
|
|
|
330
331
|
process.exit(0);
|
|
331
332
|
}
|
|
332
333
|
function cleanup() {
|
|
333
|
-
removeSocketFile();
|
|
334
|
+
removeSocketFile(socketPath);
|
|
334
335
|
rmSync(pidFile, { force: true });
|
|
335
336
|
}
|
|
336
337
|
}
|
|
337
|
-
function removeSocketFile() {
|
|
338
|
-
// Windows named pipes are not filesystem entries, so unlinking them fails with EPERM.
|
|
339
|
-
if (process.platform === "win32")
|
|
340
|
-
return;
|
|
341
|
-
rmSync(socketPath, { force: true });
|
|
342
|
-
}
|
|
343
338
|
if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
344
339
|
startDaemon();
|
|
345
340
|
}
|
package/dist/event-queue.d.ts
CHANGED
|
@@ -74,8 +74,15 @@ export declare class EventQueue {
|
|
|
74
74
|
private readonly maxSize;
|
|
75
75
|
constructor(maxSize?: number);
|
|
76
76
|
push(event: VBEvent): void;
|
|
77
|
+
/** Bubble the element at `idx` leftward to restore sorted order. */
|
|
78
|
+
private _insertionSort;
|
|
77
79
|
/**
|
|
78
|
-
* Return all events within the last `ms` milliseconds before `before
|
|
80
|
+
* Return all events within the last `ms` milliseconds before `before`.
|
|
81
|
+
*
|
|
82
|
+
* Uses binary search to find the start index (O(log n)) then slices,
|
|
83
|
+
* which is significantly faster than a full linear scan for large queues.
|
|
84
|
+
* Events are maintained in insertion order, which for timestamped pushes
|
|
85
|
+
* is monotonically non-decreasing.
|
|
79
86
|
*/
|
|
80
87
|
window(ms: number, before?: number): VBEvent[];
|
|
81
88
|
/**
|
|
@@ -83,5 +90,7 @@ export declare class EventQueue {
|
|
|
83
90
|
*/
|
|
84
91
|
ofType(type: VBEventType): VBEvent[];
|
|
85
92
|
all(): VBEvent[];
|
|
93
|
+
/** Number of events currently stored */
|
|
94
|
+
get size(): number;
|
|
86
95
|
clear(): void;
|
|
87
96
|
}
|
package/dist/event-queue.js
CHANGED
|
@@ -9,13 +9,59 @@ export class EventQueue {
|
|
|
9
9
|
if (this.events.length > this.maxSize) {
|
|
10
10
|
this.events.shift();
|
|
11
11
|
}
|
|
12
|
+
// Maintain sorted order by timestamp. Events almost always arrive
|
|
13
|
+
// in order, so the fast path (no swap) costs a single comparison.
|
|
14
|
+
const len = this.events.length;
|
|
15
|
+
if (len >= 2 && this.events[len - 1].timestamp < this.events[len - 2].timestamp) {
|
|
16
|
+
this._insertionSort(len - 1);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/** Bubble the element at `idx` leftward to restore sorted order. */
|
|
20
|
+
_insertionSort(idx) {
|
|
21
|
+
const events = this.events;
|
|
22
|
+
const item = events[idx];
|
|
23
|
+
let j = idx - 1;
|
|
24
|
+
while (j >= 0 && events[j].timestamp > item.timestamp) {
|
|
25
|
+
events[j + 1] = events[j];
|
|
26
|
+
j--;
|
|
27
|
+
}
|
|
28
|
+
events[j + 1] = item;
|
|
12
29
|
}
|
|
13
30
|
/**
|
|
14
|
-
* Return all events within the last `ms` milliseconds before `before
|
|
31
|
+
* Return all events within the last `ms` milliseconds before `before`.
|
|
32
|
+
*
|
|
33
|
+
* Uses binary search to find the start index (O(log n)) then slices,
|
|
34
|
+
* which is significantly faster than a full linear scan for large queues.
|
|
35
|
+
* Events are maintained in insertion order, which for timestamped pushes
|
|
36
|
+
* is monotonically non-decreasing.
|
|
15
37
|
*/
|
|
16
38
|
window(ms, before = Date.now()) {
|
|
17
39
|
const start = before - ms;
|
|
18
|
-
|
|
40
|
+
const events = this.events;
|
|
41
|
+
const len = events.length;
|
|
42
|
+
if (len === 0)
|
|
43
|
+
return [];
|
|
44
|
+
// Binary search for the first event with timestamp >= start
|
|
45
|
+
let lo = 0;
|
|
46
|
+
let hi = len;
|
|
47
|
+
while (lo < hi) {
|
|
48
|
+
const mid = (lo + hi) >>> 1;
|
|
49
|
+
if (events[mid].timestamp < start) {
|
|
50
|
+
lo = mid + 1;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
hi = mid;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Linear scan from lo for events <= before
|
|
57
|
+
// (in practice, `before` is usually Date.now() so most events qualify)
|
|
58
|
+
const result = [];
|
|
59
|
+
for (let i = lo; i < len; i++) {
|
|
60
|
+
if (events[i].timestamp > before)
|
|
61
|
+
break;
|
|
62
|
+
result.push(events[i]);
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
19
65
|
}
|
|
20
66
|
/**
|
|
21
67
|
* Return all events of a given type
|
|
@@ -26,6 +72,10 @@ export class EventQueue {
|
|
|
26
72
|
all() {
|
|
27
73
|
return [...this.events];
|
|
28
74
|
}
|
|
75
|
+
/** Number of events currently stored */
|
|
76
|
+
get size() {
|
|
77
|
+
return this.events.length;
|
|
78
|
+
}
|
|
29
79
|
clear() {
|
|
30
80
|
this.events = [];
|
|
31
81
|
}
|
package/dist/paths.d.ts
CHANGED
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
export declare const isWindows: boolean;
|
|
2
|
+
export declare const isLinux: boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Sanitize a session name for safe use in file paths and pipe names.
|
|
5
|
+
*/
|
|
6
|
+
export declare function sanitizeSession(name: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Resolve the base directory for vite-browser runtime files.
|
|
9
|
+
*
|
|
10
|
+
* Uses `~/.vite-browser` on all platforms.
|
|
11
|
+
* Falls back to `$TMPDIR/vite-browser-<uid>` when the home directory
|
|
12
|
+
* is not writable (e.g. some CI/container environments).
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveSocketDir(): string;
|
|
1
15
|
export declare const socketDir: string;
|
|
16
|
+
/**
|
|
17
|
+
* Socket path for the daemon.
|
|
18
|
+
*
|
|
19
|
+
* - Windows: uses a named pipe `\\.\pipe\vite-browser-<session>`
|
|
20
|
+
* - Unix: uses a Unix domain socket file in socketDir
|
|
21
|
+
*
|
|
22
|
+
* Note: Unix socket paths have a ~104-char limit on macOS and ~108 on
|
|
23
|
+
* Linux. The `~/.vite-browser/<session>.sock` path is well within
|
|
24
|
+
* that range. The tmpdir fallback may produce longer paths; we keep
|
|
25
|
+
* them short by using numeric uid.
|
|
26
|
+
*/
|
|
2
27
|
export declare const socketPath: string;
|
|
3
28
|
export declare const pidFile: string;
|
package/dist/paths.js
CHANGED
|
@@ -1,8 +1,46 @@
|
|
|
1
|
-
import { homedir } from "node:os";
|
|
1
|
+
import { homedir, tmpdir } from "node:os";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
const isWindows = process.platform === "win32";
|
|
4
|
-
const
|
|
5
|
-
|
|
3
|
+
export const isWindows = process.platform === "win32";
|
|
4
|
+
export const isLinux = process.platform === "linux";
|
|
5
|
+
/**
|
|
6
|
+
* Sanitize a session name for safe use in file paths and pipe names.
|
|
7
|
+
*/
|
|
8
|
+
export function sanitizeSession(name) {
|
|
9
|
+
return name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
10
|
+
}
|
|
11
|
+
const session = sanitizeSession(process.env.VITE_BROWSER_SESSION || "default");
|
|
12
|
+
/**
|
|
13
|
+
* Resolve the base directory for vite-browser runtime files.
|
|
14
|
+
*
|
|
15
|
+
* Uses `~/.vite-browser` on all platforms.
|
|
16
|
+
* Falls back to `$TMPDIR/vite-browser-<uid>` when the home directory
|
|
17
|
+
* is not writable (e.g. some CI/container environments).
|
|
18
|
+
*/
|
|
19
|
+
export function resolveSocketDir() {
|
|
20
|
+
try {
|
|
21
|
+
const home = homedir();
|
|
22
|
+
if (home)
|
|
23
|
+
return join(home, ".vite-browser");
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// homedir() can throw on misconfigured systems
|
|
27
|
+
}
|
|
28
|
+
// Fallback: use tmpdir scoped by uid to avoid collisions
|
|
29
|
+
const uid = process.getuid?.() ?? process.pid;
|
|
30
|
+
return join(tmpdir(), `vite-browser-${uid}`);
|
|
31
|
+
}
|
|
32
|
+
export const socketDir = resolveSocketDir();
|
|
33
|
+
/**
|
|
34
|
+
* Socket path for the daemon.
|
|
35
|
+
*
|
|
36
|
+
* - Windows: uses a named pipe `\\.\pipe\vite-browser-<session>`
|
|
37
|
+
* - Unix: uses a Unix domain socket file in socketDir
|
|
38
|
+
*
|
|
39
|
+
* Note: Unix socket paths have a ~104-char limit on macOS and ~108 on
|
|
40
|
+
* Linux. The `~/.vite-browser/<session>.sock` path is well within
|
|
41
|
+
* that range. The tmpdir fallback may produce longer paths; we keep
|
|
42
|
+
* them short by using numeric uid.
|
|
43
|
+
*/
|
|
6
44
|
export const socketPath = isWindows
|
|
7
45
|
? `\\\\.\\pipe\\vite-browser-${session}`
|
|
8
46
|
: join(socketDir, `${session}.sock`);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React DevTools Hook Management
|
|
3
|
+
*
|
|
4
|
+
* Provides health checks and auto-injection for the bundled React DevTools hook.
|
|
5
|
+
* This removes the dependency on external browser extensions for React inspection.
|
|
6
|
+
*/
|
|
7
|
+
import type { Page } from "playwright";
|
|
8
|
+
/**
|
|
9
|
+
* Get the hook source code, lazily loaded and cached
|
|
10
|
+
*/
|
|
11
|
+
export declare function getHookSource(): string;
|
|
12
|
+
export interface HookHealthStatus {
|
|
13
|
+
installed: boolean;
|
|
14
|
+
hasRenderers: boolean;
|
|
15
|
+
rendererCount: number;
|
|
16
|
+
hasFiberSupport: boolean;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Check the health of the React DevTools hook in the page
|
|
20
|
+
*/
|
|
21
|
+
export declare function checkHookHealth(page: Page): Promise<HookHealthStatus>;
|
|
22
|
+
/**
|
|
23
|
+
* Inject the React DevTools hook into a page if not already present
|
|
24
|
+
*/
|
|
25
|
+
export declare function injectHook(page: Page): Promise<boolean>;
|
|
26
|
+
/**
|
|
27
|
+
* Format hook health status for CLI output
|
|
28
|
+
*/
|
|
29
|
+
export declare function formatHookHealth(status: HookHealthStatus): string;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React DevTools Hook Management
|
|
3
|
+
*
|
|
4
|
+
* Provides health checks and auto-injection for the bundled React DevTools hook.
|
|
5
|
+
* This removes the dependency on external browser extensions for React inspection.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync } from "node:fs";
|
|
8
|
+
import { resolve } from "node:path";
|
|
9
|
+
/** Path to the bundled React DevTools hook */
|
|
10
|
+
const hookPath = resolve(import.meta.dirname, "./hook.js");
|
|
11
|
+
/** Cached hook source code */
|
|
12
|
+
let hookSource = null;
|
|
13
|
+
/**
|
|
14
|
+
* Get the hook source code, lazily loaded and cached
|
|
15
|
+
*/
|
|
16
|
+
export function getHookSource() {
|
|
17
|
+
if (!hookSource) {
|
|
18
|
+
hookSource = readFileSync(hookPath, "utf-8");
|
|
19
|
+
}
|
|
20
|
+
return hookSource;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Check the health of the React DevTools hook in the page
|
|
24
|
+
*/
|
|
25
|
+
export async function checkHookHealth(page) {
|
|
26
|
+
return page.evaluate(inPageCheckHookHealth);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Inject the React DevTools hook into a page if not already present
|
|
30
|
+
*/
|
|
31
|
+
export async function injectHook(page) {
|
|
32
|
+
const alreadyInstalled = await page.evaluate(() => !!window.__REACT_DEVTOOLS_GLOBAL_HOOK__);
|
|
33
|
+
if (alreadyInstalled)
|
|
34
|
+
return false;
|
|
35
|
+
await page.evaluate(getHookSource());
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Format hook health status for CLI output
|
|
40
|
+
*/
|
|
41
|
+
export function formatHookHealth(status) {
|
|
42
|
+
const lines = ["# React DevTools Hook Status\n"];
|
|
43
|
+
lines.push(`Installed: ${status.installed ? "✅ Yes" : "❌ No"}`);
|
|
44
|
+
lines.push(`Fiber support: ${status.hasFiberSupport ? "✅ Yes" : "❌ No"}`);
|
|
45
|
+
lines.push(`Renderers: ${status.rendererCount}`);
|
|
46
|
+
lines.push(`Has renderers: ${status.hasRenderers ? "✅ Yes" : "❌ No"}`);
|
|
47
|
+
if (!status.installed) {
|
|
48
|
+
lines.push("\n⚠️ Hook not installed. React DevTools features will not work.");
|
|
49
|
+
lines.push("The hook should be injected before React loads.");
|
|
50
|
+
}
|
|
51
|
+
else if (!status.hasRenderers) {
|
|
52
|
+
lines.push("\n⚠️ No React renderers detected.");
|
|
53
|
+
lines.push("This page may not be using React, or React hasn't mounted yet.");
|
|
54
|
+
}
|
|
55
|
+
return lines.join("\n");
|
|
56
|
+
}
|
|
57
|
+
// In-page functions
|
|
58
|
+
function inPageCheckHookHealth() {
|
|
59
|
+
const hook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
|
60
|
+
if (!hook) {
|
|
61
|
+
return {
|
|
62
|
+
installed: false,
|
|
63
|
+
hasRenderers: false,
|
|
64
|
+
rendererCount: 0,
|
|
65
|
+
hasFiberSupport: false,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const rendererCount = hook.renderers?.size ?? 0;
|
|
69
|
+
return {
|
|
70
|
+
installed: true,
|
|
71
|
+
hasRenderers: rendererCount > 0,
|
|
72
|
+
rendererCount,
|
|
73
|
+
hasFiberSupport: !!hook.supportsFiber,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|