@presto1314w/vite-devtools-browser 0.3.2 → 0.3.3
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/README.md +4 -2
- package/dist/browser.d.ts +11 -0
- package/dist/browser.js +19 -1
- package/dist/cli.js +0 -0
- package/dist/daemon.js +88 -10
- package/dist/trace.js +5 -4
- package/package.json +63 -65
package/README.md
CHANGED
|
@@ -271,13 +271,15 @@ vite-browser eval <script>
|
|
|
271
271
|
|
|
272
272
|
## Current Boundaries
|
|
273
273
|
|
|
274
|
-
`v0.3.
|
|
274
|
+
`v0.3.3` is strong at:
|
|
275
275
|
- surfacing runtime state as structured shell output
|
|
276
276
|
- linking current errors to recent HMR and module activity
|
|
277
277
|
- detecting common HMR failure patterns with confidence levels
|
|
278
278
|
- narrowing likely store/module -> render paths in Vue-first flows
|
|
279
279
|
- capturing browser-side runtime errors even when the Vite overlay is absent
|
|
280
|
-
-
|
|
280
|
+
- correlating sparse HMR traces back to the right source module more reliably
|
|
281
|
+
- retaining `changedKeys` and source-module hints when one side of the event stream is incomplete
|
|
282
|
+
- clearing stale runtime errors after recovery so the current page lifecycle is easier to trust
|
|
281
283
|
|
|
282
284
|
`correlate renders` and `diagnose propagation` are **high-confidence propagation clues**, not strict causal proof. They do not reliably trace deep chains like `store -> component A -> component B -> error` across arbitrary graphs, and intentionally fall back to conservative output when evidence is incomplete.
|
|
283
285
|
|
package/dist/browser.d.ts
CHANGED
|
@@ -7,6 +7,17 @@ export { formatHmrTrace, formatModuleGraphSnapshot, formatModuleGraphTrace, form
|
|
|
7
7
|
export type ModuleGraphMode = "snapshot" | "trace" | "clear";
|
|
8
8
|
export declare function setEventQueue(queue: EventQueue): void;
|
|
9
9
|
export declare function getEventQueue(): EventQueue | null;
|
|
10
|
+
export declare function getTrackedHmrEvents(windowMs?: number): Array<{
|
|
11
|
+
timestamp: number;
|
|
12
|
+
type: "hmr-update" | "hmr-error";
|
|
13
|
+
payload: {
|
|
14
|
+
path?: string;
|
|
15
|
+
message?: string;
|
|
16
|
+
updates?: Array<{
|
|
17
|
+
path?: string;
|
|
18
|
+
}>;
|
|
19
|
+
};
|
|
20
|
+
}>;
|
|
10
21
|
export declare function getCurrentPage(): Page | null;
|
|
11
22
|
/**
|
|
12
23
|
* Flush browser events into daemon event queue
|
package/dist/browser.js
CHANGED
|
@@ -19,6 +19,20 @@ export function setEventQueue(queue) {
|
|
|
19
19
|
export function getEventQueue() {
|
|
20
20
|
return eventQueue;
|
|
21
21
|
}
|
|
22
|
+
export function getTrackedHmrEvents(windowMs = 5000) {
|
|
23
|
+
const cutoff = Date.now() - windowMs;
|
|
24
|
+
return session.hmrEvents
|
|
25
|
+
.filter((event) => event.timestamp >= cutoff)
|
|
26
|
+
.map((event) => ({
|
|
27
|
+
timestamp: event.timestamp,
|
|
28
|
+
type: event.type === "error" ? "hmr-error" : "hmr-update",
|
|
29
|
+
payload: {
|
|
30
|
+
path: event.path,
|
|
31
|
+
message: event.message,
|
|
32
|
+
updates: event.path ? [{ path: event.path }] : [],
|
|
33
|
+
},
|
|
34
|
+
}));
|
|
35
|
+
}
|
|
22
36
|
export function getCurrentPage() {
|
|
23
37
|
return getSessionPage(session);
|
|
24
38
|
}
|
|
@@ -150,7 +164,7 @@ export async function goto(url) {
|
|
|
150
164
|
}
|
|
151
165
|
export async function back() {
|
|
152
166
|
const currentPage = await ensurePage();
|
|
153
|
-
await currentPage.goBack({ waitUntil: "domcontentloaded" });
|
|
167
|
+
await navigateAndRefreshContext(currentPage, () => currentPage.goBack({ waitUntil: "domcontentloaded" }));
|
|
154
168
|
}
|
|
155
169
|
export async function reload() {
|
|
156
170
|
const currentPage = await ensurePage();
|
|
@@ -317,8 +331,12 @@ function requireCurrentPage() {
|
|
|
317
331
|
}
|
|
318
332
|
async function navigateAndRefreshContext(currentPage, navigate, refreshFramework = false) {
|
|
319
333
|
await navigate();
|
|
334
|
+
clearRuntimeErrors();
|
|
320
335
|
await injectEventCollector(currentPage);
|
|
321
336
|
if (refreshFramework) {
|
|
322
337
|
await detectFramework();
|
|
323
338
|
}
|
|
324
339
|
}
|
|
340
|
+
function clearRuntimeErrors() {
|
|
341
|
+
session.runtimeErrors.length = 0;
|
|
342
|
+
}
|
package/dist/cli.js
CHANGED
|
File without changes
|
package/dist/daemon.js
CHANGED
|
@@ -6,6 +6,7 @@ import * as browser from "./browser.js";
|
|
|
6
6
|
import { correlateErrorWithHMR, formatErrorCorrelationReport } from "./correlate.js";
|
|
7
7
|
import { diagnoseHMR, formatDiagnosisReport } from "./diagnose.js";
|
|
8
8
|
import { diagnosePropagation, formatPropagationDiagnosisReport } from "./diagnose-propagation.js";
|
|
9
|
+
import { extractModules } from "./event-analysis.js";
|
|
9
10
|
import { socketDir, socketPath, pidFile } from "./paths.js";
|
|
10
11
|
import { correlateRenderPropagation, formatPropagationTraceReport } from "./trace.js";
|
|
11
12
|
import { EventQueue } from "./event-queue.js";
|
|
@@ -100,12 +101,20 @@ export function createRunner(api = browser) {
|
|
|
100
101
|
if (cmd.action === "correlate-errors") {
|
|
101
102
|
const errorText = String(await api.errors(Boolean(cmd.mapped), Boolean(cmd.inlineSource)));
|
|
102
103
|
const events = queue ? queue.window(cmd.windowMs ?? 5000) : [];
|
|
103
|
-
const
|
|
104
|
+
const fallbackHmrEvents = readTrackedHmrEvents(api, cmd.windowMs ?? 5000);
|
|
105
|
+
const hmrTraceText = String(await api.viteHMRTrace("trace", 20));
|
|
106
|
+
const fallbackModules = extractModules(hmrTraceText);
|
|
107
|
+
const baseCorrelation = errorText === "no errors"
|
|
108
|
+
? null
|
|
109
|
+
: correlateErrorWithHMR(errorText, [...events, ...fallbackHmrEvents], cmd.windowMs ?? 5000);
|
|
110
|
+
const data = formatErrorCorrelationReport(errorText, errorText === "no errors"
|
|
111
|
+
? null
|
|
112
|
+
: upgradeErrorCorrelation(baseCorrelation, fallbackModules, cmd.windowMs ?? 5000));
|
|
104
113
|
return { ok: true, data };
|
|
105
114
|
}
|
|
106
115
|
if (cmd.action === "correlate-renders") {
|
|
107
116
|
const events = await getSettledEventWindow(api, queue, cmd.windowMs ?? 5000);
|
|
108
|
-
const data = formatPropagationTraceReport(await buildPropagationTrace(api, events));
|
|
117
|
+
const data = formatPropagationTraceReport(await buildPropagationTrace(api, events, cmd.windowMs ?? 5000));
|
|
109
118
|
return { ok: true, data };
|
|
110
119
|
}
|
|
111
120
|
if (cmd.action === "diagnose-hmr") {
|
|
@@ -119,7 +128,7 @@ export function createRunner(api = browser) {
|
|
|
119
128
|
}
|
|
120
129
|
if (cmd.action === "diagnose-propagation") {
|
|
121
130
|
const events = await getSettledEventWindow(api, queue, cmd.windowMs ?? 5000);
|
|
122
|
-
const data = formatPropagationDiagnosisReport(diagnosePropagation(await buildPropagationTrace(api, events)));
|
|
131
|
+
const data = formatPropagationDiagnosisReport(diagnosePropagation(await buildPropagationTrace(api, events, cmd.windowMs ?? 5000)));
|
|
123
132
|
return { ok: true, data };
|
|
124
133
|
}
|
|
125
134
|
if (cmd.action === "logs") {
|
|
@@ -146,20 +155,89 @@ export function createRunner(api = browser) {
|
|
|
146
155
|
return { ok: false, error: `unknown action: ${cmd.action}` };
|
|
147
156
|
};
|
|
148
157
|
}
|
|
149
|
-
async function buildPropagationTrace(api, events) {
|
|
150
|
-
const
|
|
158
|
+
async function buildPropagationTrace(api, events, windowMs) {
|
|
159
|
+
const hmrTraceText = String(await api.viteHMRTrace("trace", 20));
|
|
160
|
+
const fallbackModules = extractModules(hmrTraceText);
|
|
161
|
+
const trace = correlateRenderPropagation([...events, ...readTrackedHmrEvents(api, windowMs)]);
|
|
151
162
|
if (!trace)
|
|
152
163
|
return null;
|
|
153
|
-
|
|
154
|
-
|
|
164
|
+
let augmented = trace;
|
|
165
|
+
if (augmented.sourceModules.length === 0 && fallbackModules.length > 0) {
|
|
166
|
+
augmented = {
|
|
167
|
+
...augmented,
|
|
168
|
+
sourceModules: fallbackModules,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
if (augmented.changedKeys.length === 0 && augmented.storeUpdates.length > 0) {
|
|
172
|
+
const inferredChangedKeys = await inferLikelyChangedKeys(api, augmented.storeUpdates[0]);
|
|
173
|
+
if (inferredChangedKeys.length > 0) {
|
|
174
|
+
augmented = {
|
|
175
|
+
...augmented,
|
|
176
|
+
changedKeys: inferredChangedKeys,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (augmented.errorMessages.length > 0)
|
|
181
|
+
return augmented;
|
|
155
182
|
const currentError = String(await api.errors(false, false));
|
|
156
183
|
if (!currentError || currentError === "no errors")
|
|
157
|
-
return
|
|
184
|
+
return augmented;
|
|
185
|
+
return {
|
|
186
|
+
...augmented,
|
|
187
|
+
errorMessages: [currentError, ...augmented.errorMessages],
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function upgradeErrorCorrelation(correlation, fallbackModules, windowMs) {
|
|
191
|
+
if (fallbackModules.length === 0)
|
|
192
|
+
return correlation;
|
|
193
|
+
if (!correlation)
|
|
194
|
+
return synthesizeErrorCorrelation(fallbackModules, windowMs);
|
|
195
|
+
if (correlation.matchingModules.length > 0)
|
|
196
|
+
return correlation;
|
|
197
|
+
return synthesizeErrorCorrelation(fallbackModules, windowMs, correlation.relatedEvents);
|
|
198
|
+
}
|
|
199
|
+
function synthesizeErrorCorrelation(modules, windowMs, relatedEvents = []) {
|
|
200
|
+
if (modules.length === 0)
|
|
201
|
+
return null;
|
|
158
202
|
return {
|
|
159
|
-
|
|
160
|
-
|
|
203
|
+
summary: `HMR update observed within ${windowMs}ms of the current error`,
|
|
204
|
+
detail: `Matching modules: ${modules.join(", ")}\nRecent events considered: ${modules.length}`,
|
|
205
|
+
confidence: "high",
|
|
206
|
+
windowMs,
|
|
207
|
+
matchingModules: modules,
|
|
208
|
+
relatedEvents: relatedEvents.length > 0
|
|
209
|
+
? relatedEvents
|
|
210
|
+
: modules.map((module) => ({
|
|
211
|
+
timestamp: Date.now(),
|
|
212
|
+
type: "hmr-update",
|
|
213
|
+
payload: {
|
|
214
|
+
path: module,
|
|
215
|
+
updates: [{ path: module }],
|
|
216
|
+
},
|
|
217
|
+
})),
|
|
161
218
|
};
|
|
162
219
|
}
|
|
220
|
+
async function inferLikelyChangedKeys(api, storeName) {
|
|
221
|
+
try {
|
|
222
|
+
const raw = await api.evaluate(`(() => {
|
|
223
|
+
const store = window.__PINIA__?._s?.get(${JSON.stringify(storeName)});
|
|
224
|
+
if (!store) return [];
|
|
225
|
+
return Object.keys(store).filter((key) => store[key] === undefined);
|
|
226
|
+
})()`);
|
|
227
|
+
const parsed = JSON.parse(String(raw));
|
|
228
|
+
return Array.isArray(parsed) ? parsed.filter((value) => typeof value === "string" && value.length > 0) : [];
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return [];
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function readTrackedHmrEvents(api, windowMs) {
|
|
235
|
+
const reader = api.getTrackedHmrEvents;
|
|
236
|
+
if (typeof reader !== "function")
|
|
237
|
+
return [];
|
|
238
|
+
const events = reader(windowMs);
|
|
239
|
+
return Array.isArray(events) ? events : [];
|
|
240
|
+
}
|
|
163
241
|
async function flushCurrentPageEvents(api, queue) {
|
|
164
242
|
if (!queue)
|
|
165
243
|
return;
|
package/dist/trace.js
CHANGED
|
@@ -21,11 +21,12 @@ export function correlateRenderPropagation(events) {
|
|
|
21
21
|
: storeHints.length === 1
|
|
22
22
|
? storeHints
|
|
23
23
|
: [];
|
|
24
|
-
const changedKeys = uniqueStrings(
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
const changedKeys = uniqueStrings([
|
|
25
|
+
...storeEvents.flatMap((event) => getChangedKeys(event.payload)),
|
|
26
|
+
...renderEvents
|
|
27
27
|
.filter((event) => getRenderReason(event.payload) === "store-update")
|
|
28
|
-
.flatMap((event) => getRenderChangedKeys(event.payload))
|
|
28
|
+
.flatMap((event) => getRenderChangedKeys(event.payload)),
|
|
29
|
+
]);
|
|
29
30
|
const renderComponents = uniqueStrings(renderEvents.map((event) => getRenderLabel(event.payload)).filter(Boolean));
|
|
30
31
|
const networkUrls = uniqueStrings(networkEvents.map((event) => getNetworkUrl(event.payload)).filter((value) => value != null));
|
|
31
32
|
const errorMessages = uniqueStrings(errorEvents.map((event) => getErrorMessage(event.payload)).filter((value) => value != null));
|
package/package.json
CHANGED
|
@@ -1,65 +1,63 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@presto1314w/vite-devtools-browser",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "Runtime diagnostics CLI for Vite apps with event-stream correlation, HMR diagnosis, framework inspection, and mapped errors",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"keywords": [
|
|
7
|
-
"vite",
|
|
8
|
-
"devtools",
|
|
9
|
-
"debugging",
|
|
10
|
-
"runtime-diagnostics",
|
|
11
|
-
"hmr",
|
|
12
|
-
"module-graph",
|
|
13
|
-
"sourcemap",
|
|
14
|
-
"vue",
|
|
15
|
-
"react",
|
|
16
|
-
"svelte",
|
|
17
|
-
"cli",
|
|
18
|
-
"ai-agents"
|
|
19
|
-
],
|
|
20
|
-
"repository": {
|
|
21
|
-
"type": "git",
|
|
22
|
-
"url": "git+https://github.com/MapleCity1314/vite-browser.git"
|
|
23
|
-
},
|
|
24
|
-
"homepage": "https://github.com/MapleCity1314/vite-browser#readme",
|
|
25
|
-
"bugs": {
|
|
26
|
-
"url": "https://github.com/MapleCity1314/vite-browser/issues"
|
|
27
|
-
},
|
|
28
|
-
"type": "module",
|
|
29
|
-
"engines": {
|
|
30
|
-
"node": ">=20"
|
|
31
|
-
},
|
|
32
|
-
"files": [
|
|
33
|
-
"dist"
|
|
34
|
-
],
|
|
35
|
-
"bin": {
|
|
36
|
-
"vite-browser": "dist/cli.js"
|
|
37
|
-
},
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
},
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
"packageManager": "pnpm@10.29.2"
|
|
65
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@presto1314w/vite-devtools-browser",
|
|
3
|
+
"version": "0.3.3",
|
|
4
|
+
"description": "Runtime diagnostics CLI for Vite apps with event-stream correlation, HMR diagnosis, framework inspection, and mapped errors",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"vite",
|
|
8
|
+
"devtools",
|
|
9
|
+
"debugging",
|
|
10
|
+
"runtime-diagnostics",
|
|
11
|
+
"hmr",
|
|
12
|
+
"module-graph",
|
|
13
|
+
"sourcemap",
|
|
14
|
+
"vue",
|
|
15
|
+
"react",
|
|
16
|
+
"svelte",
|
|
17
|
+
"cli",
|
|
18
|
+
"ai-agents"
|
|
19
|
+
],
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/MapleCity1314/vite-browser.git"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/MapleCity1314/vite-browser#readme",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/MapleCity1314/vite-browser/issues"
|
|
27
|
+
},
|
|
28
|
+
"type": "module",
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=20"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist"
|
|
34
|
+
],
|
|
35
|
+
"bin": {
|
|
36
|
+
"vite-browser": "dist/cli.js"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"playwright": "^1.50.0",
|
|
40
|
+
"source-map-js": "^1.2.1"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/node": "^22.0.0",
|
|
44
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
45
|
+
"@vue/devtools-kit": "^7.3.2",
|
|
46
|
+
"@vue/devtools-api": "^7.3.2",
|
|
47
|
+
"tsx": "^4.20.6",
|
|
48
|
+
"typescript": "^5.7.0",
|
|
49
|
+
"vitest": "^4.0.16"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"start": "node --import tsx src/cli.ts",
|
|
53
|
+
"dev": "tsx src/cli.ts",
|
|
54
|
+
"typecheck": "tsc --noEmit",
|
|
55
|
+
"build": "tsc -p tsconfig.build.json",
|
|
56
|
+
"test": "vitest run",
|
|
57
|
+
"test:watch": "vitest",
|
|
58
|
+
"test:coverage": "vitest run --coverage",
|
|
59
|
+
"test:evals": "vitest run --dir test/evals",
|
|
60
|
+
"test:evals:ci": "vitest run --dir test/evals --coverage --reporter=default",
|
|
61
|
+
"test:evals:e2e": "pnpm build && vitest run --config vitest.e2e.config.ts"
|
|
62
|
+
}
|
|
63
|
+
}
|