@presto1314w/vite-devtools-browser 0.1.3 → 0.1.4
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 +86 -69
- package/dist/browser.d.ts +34 -1
- package/dist/browser.js +119 -96
- package/dist/cli.d.ts +13 -1
- package/dist/cli.js +172 -157
- package/dist/client.d.ts +24 -0
- package/dist/client.js +37 -22
- package/dist/daemon.d.ts +57 -1
- package/dist/daemon.js +147 -128
- package/dist/react/devtools.d.ts +13 -0
- package/dist/react/devtools.js +130 -128
- package/dist/sourcemap.d.ts +7 -1
- package/dist/sourcemap.js +10 -7
- package/dist/svelte/devtools.d.ts +9 -0
- package/dist/svelte/devtools.js +110 -167
- package/dist/vue/devtools.d.ts +4 -0
- package/dist/vue/devtools.js +218 -236
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
# vite-browser
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`vite-browser` is a debugging toolchain for Vite apps:
|
|
4
|
+
- Agent Skill: scenario-based debugging workflows for coding assistants
|
|
5
|
+
- CLI Runtime (`@presto1314w/vite-devtools-browser`): structured inspection of Vue/React/Svelte runtime state
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
Current documented baseline: `v0.1.4`.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
### Install Skill
|
|
6
12
|
|
|
7
13
|
```bash
|
|
8
14
|
npx skills add MapleCity1314/vite-browser
|
|
9
15
|
```
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
### Install CLI
|
|
12
18
|
|
|
13
19
|
```bash
|
|
14
20
|
npm install -g @presto1314w/vite-devtools-browser
|
|
@@ -18,100 +24,111 @@ npx playwright install chromium
|
|
|
18
24
|
## Quick Start
|
|
19
25
|
|
|
20
26
|
```bash
|
|
21
|
-
#
|
|
22
|
-
cd my-
|
|
27
|
+
# terminal A: start Vite app
|
|
28
|
+
cd my-app
|
|
23
29
|
npm run dev
|
|
24
30
|
|
|
25
|
-
#
|
|
31
|
+
# terminal B: inspect runtime
|
|
26
32
|
vite-browser open http://localhost:5173
|
|
27
|
-
vite-browser detect
|
|
28
|
-
vite-browser vue tree
|
|
29
|
-
vite-browser
|
|
30
|
-
vite-browser
|
|
31
|
-
vite-browser
|
|
32
|
-
vite-browser
|
|
33
|
-
vite-browser
|
|
33
|
+
vite-browser detect
|
|
34
|
+
vite-browser vue tree
|
|
35
|
+
vite-browser vue pinia
|
|
36
|
+
vite-browser vite runtime
|
|
37
|
+
vite-browser vite hmr trace --limit 20
|
|
38
|
+
vite-browser vite module-graph trace --limit 50
|
|
39
|
+
vite-browser errors --mapped --inline-source
|
|
40
|
+
vite-browser network
|
|
34
41
|
vite-browser close
|
|
35
42
|
```
|
|
36
43
|
|
|
37
|
-
##
|
|
44
|
+
## Core Capabilities
|
|
38
45
|
|
|
39
|
-
- Framework
|
|
40
|
-
- Vue
|
|
41
|
-
- React
|
|
42
|
-
- Svelte
|
|
43
|
-
-
|
|
44
|
-
-
|
|
45
|
-
-
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
- Vite Integration: Error tracking, HMR monitoring
|
|
46
|
+
- Framework detection: Vue/React/Svelte best-effort detection and version hinting
|
|
47
|
+
- Vue runtime inspection: component tree/details, Pinia stores/getters, Vue Router state
|
|
48
|
+
- React runtime inspection: component tree/details (props/state/hooks/context/source)
|
|
49
|
+
- Svelte runtime inspection: component tree/details when metadata is available
|
|
50
|
+
- Vite runtime diagnostics:
|
|
51
|
+
- runtime status summary
|
|
52
|
+
- HMR summary/timeline/clear
|
|
53
|
+
- module-graph snapshot/diff/clear
|
|
54
|
+
- source-mapped errors with optional inline source snippet
|
|
55
|
+
- Debug utilities: console logs, network tracing, screenshot, page `eval`
|
|
50
56
|
|
|
51
|
-
##
|
|
57
|
+
## Command Reference
|
|
52
58
|
|
|
53
|
-
### Browser
|
|
54
|
-
```bash
|
|
55
|
-
vite-browser open <url> # Launch browser and navigate
|
|
56
|
-
vite-browser close # Close browser and daemon
|
|
57
|
-
vite-browser goto <url> # Navigate to URL
|
|
58
|
-
vite-browser back # Go back
|
|
59
|
-
vite-browser reload # Reload page
|
|
60
|
-
```
|
|
59
|
+
### Browser
|
|
61
60
|
|
|
62
|
-
### Framework Detection
|
|
63
61
|
```bash
|
|
64
|
-
vite-browser
|
|
62
|
+
vite-browser open <url> [--cookies-json <file>]
|
|
63
|
+
vite-browser close
|
|
64
|
+
vite-browser goto <url>
|
|
65
|
+
vite-browser back
|
|
66
|
+
vite-browser reload
|
|
65
67
|
```
|
|
66
68
|
|
|
67
|
-
###
|
|
68
|
-
```bash
|
|
69
|
-
vite-browser vue tree # Show component tree
|
|
70
|
-
vite-browser vue tree <id> # Inspect component details
|
|
71
|
-
vite-browser vue pinia # List all Pinia stores
|
|
72
|
-
vite-browser vue pinia <store> # Inspect specific store
|
|
73
|
-
vite-browser vue router # Show router information
|
|
74
|
-
```
|
|
69
|
+
### Framework
|
|
75
70
|
|
|
76
|
-
### React DevTools
|
|
77
71
|
```bash
|
|
78
|
-
vite-browser
|
|
79
|
-
vite-browser
|
|
72
|
+
vite-browser detect
|
|
73
|
+
vite-browser vue tree [id]
|
|
74
|
+
vite-browser vue pinia [store]
|
|
75
|
+
vite-browser vue router
|
|
76
|
+
vite-browser react tree [id]
|
|
77
|
+
vite-browser svelte tree [id]
|
|
80
78
|
```
|
|
81
79
|
|
|
82
|
-
###
|
|
80
|
+
### Vite Runtime
|
|
81
|
+
|
|
83
82
|
```bash
|
|
84
|
-
vite-browser
|
|
85
|
-
vite-browser
|
|
83
|
+
vite-browser vite restart
|
|
84
|
+
vite-browser vite runtime
|
|
85
|
+
vite-browser vite hmr
|
|
86
|
+
vite-browser vite hmr trace [--limit <n>]
|
|
87
|
+
vite-browser vite hmr clear
|
|
88
|
+
vite-browser vite module-graph [--filter <txt>] [--limit <n>]
|
|
89
|
+
vite-browser vite module-graph trace [--filter <txt>] [--limit <n>]
|
|
90
|
+
vite-browser vite module-graph clear
|
|
91
|
+
vite-browser errors
|
|
92
|
+
vite-browser errors --mapped
|
|
93
|
+
vite-browser errors --mapped --inline-source
|
|
86
94
|
```
|
|
87
95
|
|
|
88
|
-
###
|
|
96
|
+
### Utilities
|
|
97
|
+
|
|
89
98
|
```bash
|
|
90
|
-
vite-browser
|
|
91
|
-
vite-browser
|
|
92
|
-
vite-browser
|
|
93
|
-
vite-browser
|
|
94
|
-
vite-browser network # List network requests
|
|
95
|
-
vite-browser network <idx> # Inspect specific request
|
|
99
|
+
vite-browser logs
|
|
100
|
+
vite-browser network [idx]
|
|
101
|
+
vite-browser screenshot
|
|
102
|
+
vite-browser eval <script>
|
|
96
103
|
```
|
|
97
104
|
|
|
98
|
-
##
|
|
105
|
+
## Skill Packs
|
|
99
106
|
|
|
100
|
-
|
|
101
|
-
- Playwright: Headed Chromium browser
|
|
102
|
-
- One Browser, One Page: Single persistent browser instance
|
|
103
|
-
- Auto-start: Daemon starts automatically on first command
|
|
107
|
+
The entry skill routes to specialized workflows:
|
|
104
108
|
|
|
105
|
-
|
|
109
|
+
- `skills/vite-browser-core-debug/SKILL.md`
|
|
110
|
+
- `skills/vite-browser-runtime-diagnostics/SKILL.md`
|
|
111
|
+
- `skills/vite-browser-network-regression/SKILL.md`
|
|
112
|
+
- `skills/vite-browser-release-smoke/SKILL.md`
|
|
106
113
|
|
|
107
|
-
|
|
108
|
-
- Chromium (via Playwright)
|
|
109
|
-
- Vite dev server running
|
|
110
|
-
- Vue/React/Svelte app for framework-specific commands
|
|
114
|
+
Router definition: [skills/SKILL.md](./skills/SKILL.md)
|
|
111
115
|
|
|
112
|
-
##
|
|
116
|
+
## Local Development
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
pnpm install
|
|
120
|
+
pnpm build
|
|
121
|
+
pnpm test
|
|
122
|
+
pnpm test:coverage
|
|
123
|
+
pnpm test:evals
|
|
124
|
+
pnpm test:evals:e2e
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Requirements
|
|
113
128
|
|
|
114
|
-
|
|
129
|
+
- Node.js `>=20`
|
|
130
|
+
- Chromium installed via Playwright
|
|
131
|
+
- Running Vite dev server
|
|
115
132
|
|
|
116
133
|
## License
|
|
117
134
|
|
package/dist/browser.d.ts
CHANGED
|
@@ -1,9 +1,40 @@
|
|
|
1
|
+
import { type BrowserContext } from "playwright";
|
|
2
|
+
import { resolveViaSourceMap } from "./sourcemap.js";
|
|
3
|
+
type HmrEventType = "connecting" | "connected" | "update" | "full-reload" | "error" | "log";
|
|
4
|
+
export type HmrEvent = {
|
|
5
|
+
timestamp: number;
|
|
6
|
+
type: HmrEventType;
|
|
7
|
+
message: string;
|
|
8
|
+
path?: string;
|
|
9
|
+
};
|
|
10
|
+
export type RuntimeSnapshot = {
|
|
11
|
+
url: string;
|
|
12
|
+
hasViteClient: boolean;
|
|
13
|
+
wsState: string;
|
|
14
|
+
hasErrorOverlay: boolean;
|
|
15
|
+
timestamp: number;
|
|
16
|
+
};
|
|
17
|
+
export type ModuleRow = {
|
|
18
|
+
url: string;
|
|
19
|
+
initiator: string;
|
|
20
|
+
durationMs: number;
|
|
21
|
+
};
|
|
22
|
+
export type ModuleGraphMode = "snapshot" | "trace" | "clear";
|
|
1
23
|
export declare function open(url: string | undefined): Promise<void>;
|
|
2
24
|
export declare function cookies(cookies: {
|
|
3
25
|
name: string;
|
|
4
26
|
value: string;
|
|
5
27
|
}[], domain: string): Promise<number>;
|
|
6
28
|
export declare function close(): Promise<void>;
|
|
29
|
+
export declare function contextUsable(current: Pick<BrowserContext, "pages"> | null): current is Pick<BrowserContext, "pages">;
|
|
30
|
+
export declare function isClosedTargetError(error: unknown): boolean;
|
|
31
|
+
export declare function recordConsoleMessage(logs: string[], events: HmrEvent[], type: string, message: string, maxLogs?: number, maxEvents?: number): void;
|
|
32
|
+
export declare function parseViteLog(message: string): HmrEvent;
|
|
33
|
+
export declare function normalizeLimit(limit: number, fallback: number, max: number): number;
|
|
34
|
+
export declare function formatRuntimeStatus(runtime: RuntimeSnapshot, currentFramework: string, events: HmrEvent[]): string;
|
|
35
|
+
export declare function formatHmrTrace(mode: "summary" | "trace", events: HmrEvent[], limit: number): string;
|
|
36
|
+
export declare function formatModuleGraphSnapshot(rows: ModuleRow[], filter?: string, limit?: number): string;
|
|
37
|
+
export declare function formatModuleGraphTrace(currentUrls: string[], previousUrls: Set<string> | null, filter?: string, limit?: number): string;
|
|
7
38
|
export declare function goto(url: string): Promise<string>;
|
|
8
39
|
export declare function back(): Promise<void>;
|
|
9
40
|
export declare function reload(): Promise<string>;
|
|
@@ -17,9 +48,11 @@ export declare function viteRestart(): Promise<string>;
|
|
|
17
48
|
export declare function viteHMR(): Promise<string>;
|
|
18
49
|
export declare function viteRuntimeStatus(): Promise<string>;
|
|
19
50
|
export declare function viteHMRTrace(mode: "summary" | "trace" | "clear", limit?: number): Promise<string>;
|
|
20
|
-
export declare function viteModuleGraph(filter?: string, limit?: number, mode?:
|
|
51
|
+
export declare function viteModuleGraph(filter?: string, limit?: number, mode?: ModuleGraphMode): Promise<string>;
|
|
21
52
|
export declare function errors(mapped?: boolean, inlineSource?: boolean): Promise<string>;
|
|
22
53
|
export declare function logs(): Promise<string>;
|
|
23
54
|
export declare function screenshot(): Promise<string>;
|
|
24
55
|
export declare function evaluate(script: string): Promise<string>;
|
|
25
56
|
export declare function network(idx?: number): Promise<string>;
|
|
57
|
+
export declare function mapStackTrace(stack: string, origin: string, inlineSource?: boolean, resolver?: typeof resolveViaSourceMap): Promise<string>;
|
|
58
|
+
export {};
|
package/dist/browser.js
CHANGED
|
@@ -71,7 +71,7 @@ async function ensurePage() {
|
|
|
71
71
|
}
|
|
72
72
|
return page;
|
|
73
73
|
}
|
|
74
|
-
function contextUsable(current) {
|
|
74
|
+
export function contextUsable(current) {
|
|
75
75
|
if (!current)
|
|
76
76
|
return false;
|
|
77
77
|
try {
|
|
@@ -82,7 +82,7 @@ function contextUsable(current) {
|
|
|
82
82
|
return false;
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
-
function isClosedTargetError(error) {
|
|
85
|
+
export function isClosedTargetError(error) {
|
|
86
86
|
if (!(error instanceof Error))
|
|
87
87
|
return false;
|
|
88
88
|
return /Target page, context or browser has been closed/i.test(error.message);
|
|
@@ -115,20 +115,22 @@ async function launch() {
|
|
|
115
115
|
}
|
|
116
116
|
function attachListeners(currentPage) {
|
|
117
117
|
currentPage.on("console", (msg) => {
|
|
118
|
-
|
|
119
|
-
consoleLogs.push(text);
|
|
120
|
-
if (consoleLogs.length > MAX_LOGS)
|
|
121
|
-
consoleLogs.shift();
|
|
122
|
-
const viteMessage = msg.text();
|
|
123
|
-
if (!viteMessage.includes("[vite]"))
|
|
124
|
-
return;
|
|
125
|
-
const event = parseViteLog(viteMessage);
|
|
126
|
-
hmrEvents.push(event);
|
|
127
|
-
if (hmrEvents.length > MAX_HMR_EVENTS)
|
|
128
|
-
hmrEvents.shift();
|
|
118
|
+
recordConsoleMessage(consoleLogs, hmrEvents, msg.type(), msg.text());
|
|
129
119
|
});
|
|
130
120
|
}
|
|
131
|
-
function
|
|
121
|
+
export function recordConsoleMessage(logs, events, type, message, maxLogs = MAX_LOGS, maxEvents = MAX_HMR_EVENTS) {
|
|
122
|
+
const text = `[${type}] ${message}`;
|
|
123
|
+
logs.push(text);
|
|
124
|
+
if (logs.length > maxLogs)
|
|
125
|
+
logs.shift();
|
|
126
|
+
if (!message.includes("[vite]"))
|
|
127
|
+
return;
|
|
128
|
+
const event = parseViteLog(message);
|
|
129
|
+
events.push(event);
|
|
130
|
+
if (events.length > maxEvents)
|
|
131
|
+
events.shift();
|
|
132
|
+
}
|
|
133
|
+
export function parseViteLog(message) {
|
|
132
134
|
const lower = message.toLowerCase();
|
|
133
135
|
const event = {
|
|
134
136
|
timestamp: Date.now(),
|
|
@@ -154,6 +156,103 @@ function parseViteLog(message) {
|
|
|
154
156
|
event.path = hotUpdateMatch[1].trim();
|
|
155
157
|
return event;
|
|
156
158
|
}
|
|
159
|
+
export function normalizeLimit(limit, fallback, max) {
|
|
160
|
+
if (!Number.isFinite(limit) || limit <= 0)
|
|
161
|
+
return fallback;
|
|
162
|
+
return Math.min(limit, max);
|
|
163
|
+
}
|
|
164
|
+
export function formatRuntimeStatus(runtime, currentFramework, events) {
|
|
165
|
+
const output = [];
|
|
166
|
+
output.push("# Vite Runtime");
|
|
167
|
+
output.push(`URL: ${runtime.url}`);
|
|
168
|
+
output.push(`Framework: ${currentFramework}`);
|
|
169
|
+
output.push(`Vite Client: ${runtime.hasViteClient ? "loaded" : "not detected"}`);
|
|
170
|
+
output.push(`HMR Socket: ${runtime.wsState}`);
|
|
171
|
+
output.push(`Error Overlay: ${runtime.hasErrorOverlay ? "present" : "none"}`);
|
|
172
|
+
output.push(`Tracked HMR Events: ${events.length}`);
|
|
173
|
+
const last = events[events.length - 1];
|
|
174
|
+
if (last) {
|
|
175
|
+
output.push(`Last HMR Event: ${new Date(last.timestamp).toLocaleTimeString()} [${last.type}] ${last.message}`);
|
|
176
|
+
}
|
|
177
|
+
return output.join("\n");
|
|
178
|
+
}
|
|
179
|
+
export function formatHmrTrace(mode, events, limit) {
|
|
180
|
+
if (events.length === 0)
|
|
181
|
+
return "No HMR updates";
|
|
182
|
+
const safeLimit = normalizeLimit(limit, 20, 200);
|
|
183
|
+
const recent = events.slice(-safeLimit);
|
|
184
|
+
if (mode === "summary") {
|
|
185
|
+
const counts = recent.reduce((acc, event) => {
|
|
186
|
+
acc[event.type] = (acc[event.type] ?? 0) + 1;
|
|
187
|
+
return acc;
|
|
188
|
+
}, {});
|
|
189
|
+
const lines = ["# HMR Summary"];
|
|
190
|
+
lines.push(`Events considered: ${recent.length}`);
|
|
191
|
+
lines.push(`Counts: ${Object.entries(counts)
|
|
192
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
193
|
+
.join(", ")}`);
|
|
194
|
+
const last = recent[recent.length - 1];
|
|
195
|
+
lines.push(`Last: ${new Date(last.timestamp).toLocaleTimeString()} [${last.type}] ${last.path ?? last.message}`);
|
|
196
|
+
lines.push("\nUse `vite-browser vite hmr trace --limit <n>` for timeline details.");
|
|
197
|
+
return lines.join("\n");
|
|
198
|
+
}
|
|
199
|
+
return [
|
|
200
|
+
"# HMR Trace",
|
|
201
|
+
...recent.map((event) => {
|
|
202
|
+
const detail = event.path ? `${event.path}` : event.message;
|
|
203
|
+
return `[${new Date(event.timestamp).toLocaleTimeString()}] ${event.type} ${detail}`;
|
|
204
|
+
}),
|
|
205
|
+
].join("\n");
|
|
206
|
+
}
|
|
207
|
+
export function formatModuleGraphSnapshot(rows, filter, limit = 200) {
|
|
208
|
+
const normalizedFilter = filter?.trim().toLowerCase();
|
|
209
|
+
const safeLimit = normalizeLimit(limit, 200, 500);
|
|
210
|
+
const filtered = rows.filter((row) => normalizedFilter ? row.url.toLowerCase().includes(normalizedFilter) : true);
|
|
211
|
+
const limited = filtered.slice(0, safeLimit);
|
|
212
|
+
if (limited.length === 0)
|
|
213
|
+
return "No module resources found";
|
|
214
|
+
const lines = [];
|
|
215
|
+
lines.push("# Vite Module Graph (loaded resources)");
|
|
216
|
+
lines.push(`Total: ${filtered.length}${filtered.length > limited.length ? ` (showing ${limited.length})` : ""}`);
|
|
217
|
+
lines.push("# idx initiator ms url");
|
|
218
|
+
lines.push("");
|
|
219
|
+
limited.forEach((row, idx) => {
|
|
220
|
+
lines.push(`${idx} ${row.initiator} ${row.durationMs}ms ${row.url}`);
|
|
221
|
+
});
|
|
222
|
+
return lines.join("\n");
|
|
223
|
+
}
|
|
224
|
+
export function formatModuleGraphTrace(currentUrls, previousUrls, filter, limit = 200) {
|
|
225
|
+
if (!previousUrls) {
|
|
226
|
+
return "No module-graph baseline. Captured current snapshot; run `vite module-graph trace` again.";
|
|
227
|
+
}
|
|
228
|
+
const currentSet = new Set(currentUrls);
|
|
229
|
+
const added = currentUrls.filter((url) => !previousUrls.has(url));
|
|
230
|
+
const removed = [...previousUrls].filter((url) => !currentSet.has(url));
|
|
231
|
+
const normalizedFilter = filter?.trim().toLowerCase();
|
|
232
|
+
const safeLimit = normalizeLimit(limit, 200, 500);
|
|
233
|
+
const addedFiltered = normalizedFilter
|
|
234
|
+
? added.filter((url) => url.toLowerCase().includes(normalizedFilter))
|
|
235
|
+
: added;
|
|
236
|
+
const removedFiltered = normalizedFilter
|
|
237
|
+
? removed.filter((url) => url.toLowerCase().includes(normalizedFilter))
|
|
238
|
+
: removed;
|
|
239
|
+
const lines = [];
|
|
240
|
+
lines.push("# Vite Module Graph Trace");
|
|
241
|
+
lines.push(`Added: ${addedFiltered.length}, Removed: ${removedFiltered.length}`);
|
|
242
|
+
lines.push("");
|
|
243
|
+
lines.push("## Added");
|
|
244
|
+
if (addedFiltered.length === 0)
|
|
245
|
+
lines.push("(none)");
|
|
246
|
+
else
|
|
247
|
+
addedFiltered.slice(0, safeLimit).forEach((url) => lines.push(`+ ${url}`));
|
|
248
|
+
lines.push("");
|
|
249
|
+
lines.push("## Removed");
|
|
250
|
+
if (removedFiltered.length === 0)
|
|
251
|
+
lines.push("(none)");
|
|
252
|
+
else
|
|
253
|
+
removedFiltered.slice(0, safeLimit).forEach((url) => lines.push(`- ${url}`));
|
|
254
|
+
return lines.join("\n");
|
|
255
|
+
}
|
|
157
256
|
export async function goto(url) {
|
|
158
257
|
const currentPage = await ensurePage();
|
|
159
258
|
await currentPage.goto(url, { waitUntil: "domcontentloaded" });
|
|
@@ -295,19 +394,7 @@ export async function viteRuntimeStatus() {
|
|
|
295
394
|
timestamp: Date.now(),
|
|
296
395
|
};
|
|
297
396
|
});
|
|
298
|
-
|
|
299
|
-
output.push("# Vite Runtime");
|
|
300
|
-
output.push(`URL: ${runtime.url}`);
|
|
301
|
-
output.push(`Framework: ${framework}`);
|
|
302
|
-
output.push(`Vite Client: ${runtime.hasViteClient ? "loaded" : "not detected"}`);
|
|
303
|
-
output.push(`HMR Socket: ${runtime.wsState}`);
|
|
304
|
-
output.push(`Error Overlay: ${runtime.hasErrorOverlay ? "present" : "none"}`);
|
|
305
|
-
output.push(`Tracked HMR Events: ${hmrEvents.length}`);
|
|
306
|
-
const last = hmrEvents[hmrEvents.length - 1];
|
|
307
|
-
if (last) {
|
|
308
|
-
output.push(`Last HMR Event: ${new Date(last.timestamp).toLocaleTimeString()} [${last.type}] ${last.message}`);
|
|
309
|
-
}
|
|
310
|
-
return output.join("\n");
|
|
397
|
+
return formatRuntimeStatus(runtime, framework, hmrEvents);
|
|
311
398
|
}
|
|
312
399
|
export async function viteHMRTrace(mode, limit = 20) {
|
|
313
400
|
if (!page)
|
|
@@ -331,30 +418,7 @@ export async function viteHMRTrace(mode, limit = 20) {
|
|
|
331
418
|
}
|
|
332
419
|
if (hmrEvents.length === 0)
|
|
333
420
|
return "No HMR updates";
|
|
334
|
-
|
|
335
|
-
const recent = hmrEvents.slice(-safeLimit);
|
|
336
|
-
if (mode === "summary") {
|
|
337
|
-
const counts = recent.reduce((acc, event) => {
|
|
338
|
-
acc[event.type] = (acc[event.type] ?? 0) + 1;
|
|
339
|
-
return acc;
|
|
340
|
-
}, {});
|
|
341
|
-
const lines = ["# HMR Summary"];
|
|
342
|
-
lines.push(`Events considered: ${recent.length}`);
|
|
343
|
-
lines.push(`Counts: ${Object.entries(counts)
|
|
344
|
-
.map(([k, v]) => `${k}=${v}`)
|
|
345
|
-
.join(", ")}`);
|
|
346
|
-
const last = recent[recent.length - 1];
|
|
347
|
-
lines.push(`Last: ${new Date(last.timestamp).toLocaleTimeString()} [${last.type}] ${last.path ?? last.message}`);
|
|
348
|
-
lines.push("\nUse `vite-browser vite hmr trace --limit <n>` for timeline details.");
|
|
349
|
-
return lines.join("\n");
|
|
350
|
-
}
|
|
351
|
-
return [
|
|
352
|
-
"# HMR Trace",
|
|
353
|
-
...recent.map((event) => {
|
|
354
|
-
const detail = event.path ? `${event.path}` : event.message;
|
|
355
|
-
return `[${new Date(event.timestamp).toLocaleTimeString()}] ${event.type} ${detail}`;
|
|
356
|
-
}),
|
|
357
|
-
].join("\n");
|
|
421
|
+
return formatHmrTrace(mode, hmrEvents, limit);
|
|
358
422
|
}
|
|
359
423
|
export async function viteModuleGraph(filter, limit = 200, mode = "snapshot") {
|
|
360
424
|
if (!page)
|
|
@@ -366,52 +430,11 @@ export async function viteModuleGraph(filter, limit = 200, mode = "snapshot") {
|
|
|
366
430
|
const moduleRows = await collectModuleRows(page);
|
|
367
431
|
const currentUrls = moduleRows.map((row) => row.url);
|
|
368
432
|
const previousUrls = lastModuleGraphUrls ? new Set(lastModuleGraphUrls) : null;
|
|
369
|
-
const currentSet = new Set(currentUrls);
|
|
370
433
|
lastModuleGraphUrls = [...currentUrls];
|
|
371
|
-
const normalizedFilter = filter?.trim().toLowerCase();
|
|
372
|
-
const safeLimit = Number.isFinite(limit) && limit > 0 ? Math.min(limit, 500) : 200;
|
|
373
434
|
if (mode === "trace") {
|
|
374
|
-
|
|
375
|
-
return "No module-graph baseline. Captured current snapshot; run `vite module-graph trace` again.";
|
|
376
|
-
}
|
|
377
|
-
const added = currentUrls.filter((url) => !previousUrls.has(url));
|
|
378
|
-
const removed = [...previousUrls].filter((url) => !currentSet.has(url));
|
|
379
|
-
const addedFiltered = normalizedFilter
|
|
380
|
-
? added.filter((url) => url.toLowerCase().includes(normalizedFilter))
|
|
381
|
-
: added;
|
|
382
|
-
const removedFiltered = normalizedFilter
|
|
383
|
-
? removed.filter((url) => url.toLowerCase().includes(normalizedFilter))
|
|
384
|
-
: removed;
|
|
385
|
-
const lines = [];
|
|
386
|
-
lines.push("# Vite Module Graph Trace");
|
|
387
|
-
lines.push(`Added: ${addedFiltered.length}, Removed: ${removedFiltered.length}`);
|
|
388
|
-
lines.push("");
|
|
389
|
-
lines.push("## Added");
|
|
390
|
-
if (addedFiltered.length === 0)
|
|
391
|
-
lines.push("(none)");
|
|
392
|
-
else
|
|
393
|
-
addedFiltered.slice(0, safeLimit).forEach((url) => lines.push(`+ ${url}`));
|
|
394
|
-
lines.push("");
|
|
395
|
-
lines.push("## Removed");
|
|
396
|
-
if (removedFiltered.length === 0)
|
|
397
|
-
lines.push("(none)");
|
|
398
|
-
else
|
|
399
|
-
removedFiltered.slice(0, safeLimit).forEach((url) => lines.push(`- ${url}`));
|
|
400
|
-
return lines.join("\n");
|
|
435
|
+
return formatModuleGraphTrace(currentUrls, previousUrls, filter, limit);
|
|
401
436
|
}
|
|
402
|
-
|
|
403
|
-
const limited = filtered.slice(0, safeLimit);
|
|
404
|
-
if (limited.length === 0)
|
|
405
|
-
return "No module resources found";
|
|
406
|
-
const lines = [];
|
|
407
|
-
lines.push("# Vite Module Graph (loaded resources)");
|
|
408
|
-
lines.push(`Total: ${filtered.length}${filtered.length > limited.length ? ` (showing ${limited.length})` : ""}`);
|
|
409
|
-
lines.push("# idx initiator ms url");
|
|
410
|
-
lines.push("");
|
|
411
|
-
limited.forEach((row, idx) => {
|
|
412
|
-
lines.push(`${idx} ${row.initiator} ${row.durationMs}ms ${row.url}`);
|
|
413
|
-
});
|
|
414
|
-
return lines.join("\n");
|
|
437
|
+
return formatModuleGraphSnapshot(moduleRows, filter, limit);
|
|
415
438
|
}
|
|
416
439
|
async function collectModuleRows(page) {
|
|
417
440
|
return page.evaluate(() => {
|
|
@@ -500,7 +523,7 @@ export async function network(idx) {
|
|
|
500
523
|
return networkLog.format();
|
|
501
524
|
return networkLog.detail(idx);
|
|
502
525
|
}
|
|
503
|
-
async function mapStackTrace(stack, origin, inlineSource = false) {
|
|
526
|
+
export async function mapStackTrace(stack, origin, inlineSource = false, resolver = resolveViaSourceMap) {
|
|
504
527
|
const locationRegex = /(https?:\/\/[^\s)]+):(\d+):(\d+)/g;
|
|
505
528
|
const matches = Array.from(stack.matchAll(locationRegex));
|
|
506
529
|
if (matches.length === 0)
|
|
@@ -512,7 +535,7 @@ async function mapStackTrace(stack, origin, inlineSource = false) {
|
|
|
512
535
|
const column = Number.parseInt(match[3], 10);
|
|
513
536
|
if (!Number.isFinite(line) || !Number.isFinite(column))
|
|
514
537
|
continue;
|
|
515
|
-
const mapped = await
|
|
538
|
+
const mapped = await resolver(origin, fileUrl, line, column, inlineSource);
|
|
516
539
|
if (!mapped)
|
|
517
540
|
continue;
|
|
518
541
|
mappedLines.push(`- ${fileUrl}:${line}:${column} -> ${mapped.file}:${mapped.line}:${mapped.column}`);
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,2 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
2
|
+
import { send, type Response } from "./client.js";
|
|
3
|
+
export type CliIo = {
|
|
4
|
+
send: typeof send;
|
|
5
|
+
readFile: (path: string, encoding: BufferEncoding) => string;
|
|
6
|
+
stdout: (text: string) => void;
|
|
7
|
+
stderr: (text: string) => void;
|
|
8
|
+
exit: (code: number) => never;
|
|
9
|
+
};
|
|
10
|
+
export declare function normalizeUrl(value: string): string;
|
|
11
|
+
export declare function parseNumberFlag(args: string[], name: string, fallback: number): number;
|
|
12
|
+
export declare function runCli(argv: string[], io: CliIo): Promise<void>;
|
|
13
|
+
export declare function exit(io: Pick<CliIo, "stdout" | "stderr" | "exit">, res: Response, msg: string): never;
|
|
14
|
+
export declare function printUsage(): string;
|