@presto1314w/vite-devtools-browser 0.1.2 → 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/dist/cli.js CHANGED
@@ -1,131 +1,176 @@
1
1
  #!/usr/bin/env node
2
2
  import { readFileSync } from "node:fs";
3
3
  import { send } from "./client.js";
4
- const args = process.argv.slice(2);
5
- const cmd = args[0];
6
- const arg = args[1];
7
- if (cmd === "--help" || cmd === "-h" || !cmd) {
8
- printUsage();
9
- process.exit(0);
10
- }
11
- if (cmd === "open") {
12
- if (!arg) {
13
- console.error("usage: vite-browser open <url> [--cookies-json <file>]");
14
- process.exit(1);
15
- }
16
- const url = normalizeUrl(arg);
17
- const cookieIdx = args.indexOf("--cookies-json");
18
- const cookieFile = cookieIdx >= 0 ? args[cookieIdx + 1] : undefined;
19
- if (cookieFile) {
20
- const res = await send("open");
21
- if (!res.ok)
22
- exit(res, "");
23
- const raw = readFileSync(cookieFile, "utf-8");
24
- const cookies = JSON.parse(raw);
25
- const domain = new URL(url).hostname;
26
- const cRes = await send("cookies", { cookies, domain });
27
- if (!cRes.ok)
28
- exit(cRes, "");
29
- await send("goto", { url });
30
- exit(res, `opened -> ${url} (${cookies.length} cookies for ${domain})`);
31
- }
32
- const res = await send("open", { url });
33
- exit(res, `opened -> ${url}`);
34
- }
35
- if (cmd === "close") {
36
- const res = await send("close");
37
- exit(res, "closed");
4
+ export function normalizeUrl(value) {
5
+ if (value.includes("://"))
6
+ return value;
7
+ return `http://${value}`;
38
8
  }
39
- if (cmd === "goto") {
40
- if (!arg) {
41
- console.error("usage: vite-browser goto <url>");
42
- process.exit(1);
9
+ export function parseNumberFlag(args, name, fallback) {
10
+ const idx = args.indexOf(name);
11
+ if (idx < 0)
12
+ return fallback;
13
+ return Number.parseInt(args[idx + 1] ?? String(fallback), 10);
14
+ }
15
+ export async function runCli(argv, io) {
16
+ const args = argv.slice(2);
17
+ const cmd = args[0];
18
+ const arg = args[1];
19
+ if (cmd === "--help" || cmd === "-h" || !cmd) {
20
+ io.stdout(printUsage());
21
+ io.exit(0);
43
22
  }
44
- const res = await send("goto", { url: normalizeUrl(arg) });
45
- exit(res, res.ok ? `-> ${res.data}` : "");
46
- }
47
- if (cmd === "back") {
48
- const res = await send("back");
49
- exit(res, "back");
50
- }
51
- if (cmd === "reload") {
52
- const res = await send("reload");
53
- exit(res, res.ok ? `reloaded -> ${res.data}` : "");
54
- }
55
- if (cmd === "detect") {
56
- const res = await send("detect");
57
- exit(res, res.ok && res.data ? String(res.data) : "");
58
- }
59
- if (cmd === "vue" && arg === "tree") {
60
- const id = args[2];
61
- const res = await send("vue-tree", { id });
62
- exit(res, res.ok && res.data ? String(res.data) : "");
63
- }
64
- if (cmd === "vue" && arg === "pinia") {
65
- const store = args[2];
66
- const res = await send("vue-pinia", { store });
67
- exit(res, res.ok && res.data ? String(res.data) : "");
68
- }
69
- if (cmd === "vue" && arg === "router") {
70
- const res = await send("vue-router");
71
- exit(res, res.ok && res.data ? String(res.data) : "");
72
- }
73
- if (cmd === "react" && arg === "tree") {
74
- const id = args[2];
75
- const res = await send("react-tree", { id });
76
- exit(res, res.ok && res.data ? String(res.data) : "");
77
- }
78
- if (cmd === "svelte" && arg === "tree") {
79
- const id = args[2];
80
- const res = await send("svelte-tree", { id });
81
- exit(res, res.ok && res.data ? String(res.data) : "");
82
- }
83
- if (cmd === "vite" && arg === "restart") {
84
- const res = await send("vite-restart");
85
- exit(res, res.ok && res.data ? String(res.data) : "restarted");
86
- }
87
- if (cmd === "vite" && arg === "hmr") {
88
- const res = await send("vite-hmr");
89
- exit(res, res.ok && res.data ? String(res.data) : "");
90
- }
91
- if (cmd === "errors") {
92
- const res = await send("errors");
93
- exit(res, res.ok && res.data ? String(res.data) : "no errors");
94
- }
95
- if (cmd === "logs") {
96
- const res = await send("logs");
97
- exit(res, res.ok && res.data ? String(res.data) : "");
98
- }
99
- if (cmd === "screenshot") {
100
- const res = await send("screenshot");
101
- exit(res, res.ok && res.data ? String(res.data) : "");
102
- }
103
- if (cmd === "eval") {
104
- if (!arg) {
105
- console.error("usage: vite-browser eval <script>");
106
- process.exit(1);
23
+ if (cmd === "open") {
24
+ if (!arg) {
25
+ io.stderr("usage: vite-browser open <url> [--cookies-json <file>]");
26
+ io.exit(1);
27
+ }
28
+ const url = normalizeUrl(arg);
29
+ const cookieIdx = args.indexOf("--cookies-json");
30
+ const cookieFile = cookieIdx >= 0 ? args[cookieIdx + 1] : undefined;
31
+ if (cookieFile) {
32
+ const res = await io.send("open");
33
+ if (!res.ok)
34
+ exit(io, res, "");
35
+ const raw = io.readFile(cookieFile, "utf-8");
36
+ const cookies = JSON.parse(raw);
37
+ const domain = new URL(url).hostname;
38
+ const cRes = await io.send("cookies", { cookies, domain });
39
+ if (!cRes.ok)
40
+ exit(io, cRes, "");
41
+ await io.send("goto", { url });
42
+ exit(io, res, `opened -> ${url} (${cookies.length} cookies for ${domain})`);
43
+ }
44
+ const res = await io.send("open", { url });
45
+ exit(io, res, `opened -> ${url}`);
107
46
  }
108
- const res = await send("eval", { script: arg });
109
- exit(res, res.ok && res.data ? String(res.data) : "");
110
- }
111
- if (cmd === "network") {
112
- const idx = arg ? parseInt(arg, 10) : undefined;
113
- const res = await send("network", { idx });
114
- exit(res, res.ok && res.data ? String(res.data) : "");
47
+ if (cmd === "close") {
48
+ const res = await io.send("close");
49
+ exit(io, res, "closed");
50
+ }
51
+ if (cmd === "goto") {
52
+ if (!arg) {
53
+ io.stderr("usage: vite-browser goto <url>");
54
+ io.exit(1);
55
+ }
56
+ const res = await io.send("goto", { url: normalizeUrl(arg) });
57
+ exit(io, res, res.ok ? `-> ${res.data}` : "");
58
+ }
59
+ if (cmd === "back") {
60
+ const res = await io.send("back");
61
+ exit(io, res, "back");
62
+ }
63
+ if (cmd === "reload") {
64
+ const res = await io.send("reload");
65
+ exit(io, res, res.ok ? `reloaded -> ${res.data}` : "");
66
+ }
67
+ if (cmd === "detect") {
68
+ const res = await io.send("detect");
69
+ exit(io, res, res.ok && res.data ? String(res.data) : "");
70
+ }
71
+ if (cmd === "vue" && arg === "tree") {
72
+ const id = args[2];
73
+ const res = await io.send("vue-tree", { id });
74
+ exit(io, res, res.ok && res.data ? String(res.data) : "");
75
+ }
76
+ if (cmd === "vue" && arg === "pinia") {
77
+ const store = args[2];
78
+ const res = await io.send("vue-pinia", { store });
79
+ exit(io, res, res.ok && res.data ? String(res.data) : "");
80
+ }
81
+ if (cmd === "vue" && arg === "router") {
82
+ const res = await io.send("vue-router");
83
+ exit(io, res, res.ok && res.data ? String(res.data) : "");
84
+ }
85
+ if (cmd === "react" && arg === "tree") {
86
+ const id = args[2];
87
+ const res = await io.send("react-tree", { id });
88
+ exit(io, res, res.ok && res.data ? String(res.data) : "");
89
+ }
90
+ if (cmd === "svelte" && arg === "tree") {
91
+ const id = args[2];
92
+ const res = await io.send("svelte-tree", { id });
93
+ exit(io, res, res.ok && res.data ? String(res.data) : "");
94
+ }
95
+ if (cmd === "vite" && arg === "restart") {
96
+ const res = await io.send("vite-restart");
97
+ exit(io, res, res.ok && res.data ? String(res.data) : "restarted");
98
+ }
99
+ if (cmd === "vite" && arg === "hmr") {
100
+ const sub = args[2];
101
+ if (sub === "clear") {
102
+ const res = await io.send("vite-hmr", { mode: "clear" });
103
+ exit(io, res, res.ok && res.data ? String(res.data) : "cleared HMR trace");
104
+ }
105
+ if (sub === "trace") {
106
+ const limit = parseNumberFlag(args, "--limit", 20);
107
+ const res = await io.send("vite-hmr", { mode: "trace", limit });
108
+ exit(io, res, res.ok && res.data ? String(res.data) : "");
109
+ }
110
+ const res = await io.send("vite-hmr", { mode: "summary", limit: 20 });
111
+ exit(io, res, res.ok && res.data ? String(res.data) : "");
112
+ }
113
+ if (cmd === "vite" && arg === "runtime") {
114
+ const res = await io.send("vite-runtime");
115
+ exit(io, res, res.ok && res.data ? String(res.data) : "");
116
+ }
117
+ if (cmd === "vite" && arg === "module-graph") {
118
+ const sub = args[2];
119
+ const filterIdx = args.indexOf("--filter");
120
+ const filter = filterIdx >= 0 ? args[filterIdx + 1] : undefined;
121
+ const limit = parseNumberFlag(args, "--limit", 200);
122
+ if (sub === "clear") {
123
+ const res = await io.send("vite-module-graph", { mode: "clear" });
124
+ exit(io, res, res.ok && res.data ? String(res.data) : "cleared module-graph baseline");
125
+ }
126
+ if (sub === "trace") {
127
+ const res = await io.send("vite-module-graph", { mode: "trace", filter, limit });
128
+ exit(io, res, res.ok && res.data ? String(res.data) : "");
129
+ }
130
+ const res = await io.send("vite-module-graph", { mode: "snapshot", filter, limit });
131
+ exit(io, res, res.ok && res.data ? String(res.data) : "");
132
+ }
133
+ if (cmd === "errors") {
134
+ const mapped = args.includes("--mapped");
135
+ const inlineSource = args.includes("--inline-source");
136
+ const res = await io.send("errors", { mapped, inlineSource });
137
+ exit(io, res, res.ok && res.data ? String(res.data) : "no errors");
138
+ }
139
+ if (cmd === "logs") {
140
+ const res = await io.send("logs");
141
+ exit(io, res, res.ok && res.data ? String(res.data) : "");
142
+ }
143
+ if (cmd === "screenshot") {
144
+ const res = await io.send("screenshot");
145
+ exit(io, res, res.ok && res.data ? String(res.data) : "");
146
+ }
147
+ if (cmd === "eval") {
148
+ if (!arg) {
149
+ io.stderr("usage: vite-browser eval <script>");
150
+ io.exit(1);
151
+ }
152
+ const res = await io.send("eval", { script: arg });
153
+ exit(io, res, res.ok && res.data ? String(res.data) : "");
154
+ }
155
+ if (cmd === "network") {
156
+ const idx = arg ? parseInt(arg, 10) : undefined;
157
+ const res = await io.send("network", { idx });
158
+ exit(io, res, res.ok && res.data ? String(res.data) : "");
159
+ }
160
+ io.stderr(`unknown command: ${cmd}`);
161
+ io.exit(1);
115
162
  }
116
- console.error(`unknown command: ${cmd}`);
117
- process.exit(1);
118
- function exit(res, msg) {
163
+ export function exit(io, res, msg) {
119
164
  if (!res.ok) {
120
- console.error(res.error || "error");
121
- process.exit(1);
165
+ io.stderr(res.error || "error");
166
+ io.exit(1);
122
167
  }
123
168
  if (msg)
124
- console.log(msg);
125
- process.exit(0);
169
+ io.stdout(msg);
170
+ io.exit(0);
126
171
  }
127
- function printUsage() {
128
- console.log(`
172
+ export function printUsage() {
173
+ return `
129
174
  vite-browser - Programmatic access to Vue/React/Svelte DevTools and Vite dev server
130
175
 
131
176
  USAGE
@@ -154,8 +199,18 @@ SVELTE COMMANDS
154
199
 
155
200
  VITE COMMANDS
156
201
  vite restart Restart Vite dev server
157
- vite hmr Show HMR status
202
+ vite hmr Show HMR summary
203
+ vite hmr trace [--limit <n>] Show HMR timeline
204
+ vite hmr clear Clear tracked HMR timeline
205
+ vite runtime Show Vite runtime status
206
+ vite module-graph [--filter <txt>] [--limit <n>]
207
+ Show loaded Vite module resources
208
+ vite module-graph trace [--filter <txt>] [--limit <n>]
209
+ Show module additions/removals since baseline
210
+ vite module-graph clear Clear module-graph baseline
158
211
  errors Show build/runtime errors
212
+ errors --mapped Show errors with source-map mapping
213
+ errors --mapped --inline-source Include mapped source snippets
159
214
  logs Show dev server logs
160
215
 
161
216
  UTILITIES
@@ -165,10 +220,14 @@ UTILITIES
165
220
 
166
221
  OPTIONS
167
222
  -h, --help Show this help message
168
- `);
169
- }
170
- function normalizeUrl(value) {
171
- if (value.includes("://"))
172
- return value;
173
- return `http://${value}`;
223
+ `;
224
+ }
225
+ if (process.argv[1] && import.meta.url.endsWith(process.argv[1].replaceAll("\\", "/"))) {
226
+ await runCli(process.argv, {
227
+ send,
228
+ readFile: readFileSync,
229
+ stdout: (text) => console.log(text),
230
+ stderr: (text) => console.error(text),
231
+ exit: (code) => process.exit(code),
232
+ });
174
233
  }
package/dist/client.d.ts CHANGED
@@ -1,3 +1,7 @@
1
+ import { type Socket } from "node:net";
2
+ import { readFileSync, existsSync, rmSync } from "node:fs";
3
+ import { spawn } from "node:child_process";
4
+ import { setTimeout as sleep } from "node:timers/promises";
1
5
  export type Response = {
2
6
  ok: true;
3
7
  data?: unknown;
@@ -5,4 +9,24 @@ export type Response = {
5
9
  ok: false;
6
10
  error: string;
7
11
  };
12
+ export type ClientDeps = {
13
+ socketPath: string;
14
+ pidFile: string;
15
+ existsSync: typeof existsSync;
16
+ readFileSync: typeof readFileSync;
17
+ rmSync: typeof rmSync;
18
+ processKill: typeof process.kill;
19
+ spawn: typeof spawn;
20
+ connect: () => Promise<Socket>;
21
+ sleep: typeof sleep;
22
+ daemonPath: string;
23
+ };
24
+ export declare function createClientDeps(): ClientDeps;
8
25
  export declare function send(action: string, payload?: Record<string, unknown>): Promise<Response>;
26
+ export declare function ensureDaemon(deps: ClientDeps): Promise<void>;
27
+ export declare function daemonAlive(deps: Pick<ClientDeps, "existsSync" | "pidFile" | "readFileSync" | "processKill" | "rmSync" | "socketPath">): boolean;
28
+ export declare function connect(): Promise<Socket>;
29
+ export declare function readLine(socket: Pick<Socket, "on">): Promise<string>;
30
+ export declare function ok(s: Pick<Socket, "destroy">): boolean;
31
+ export declare function no(): boolean;
32
+ export declare function removeSocketFile(path: string, removeFile?: typeof rmSync): void;
package/dist/client.js CHANGED
@@ -4,54 +4,69 @@ import { spawn } from "node:child_process";
4
4
  import { setTimeout as sleep } from "node:timers/promises";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { socketPath, pidFile } from "./paths.js";
7
+ export function createClientDeps() {
8
+ const ext = import.meta.url.endsWith(".ts") ? ".ts" : ".js";
9
+ const daemonPath = fileURLToPath(new URL(`./daemon${ext}`, import.meta.url));
10
+ return {
11
+ socketPath,
12
+ pidFile,
13
+ existsSync,
14
+ readFileSync,
15
+ rmSync,
16
+ processKill: process.kill.bind(process),
17
+ spawn,
18
+ connect,
19
+ sleep,
20
+ daemonPath,
21
+ };
22
+ }
7
23
  export async function send(action, payload = {}) {
8
- await ensureDaemon();
9
- const socket = await connect();
24
+ const deps = createClientDeps();
25
+ await ensureDaemon(deps);
26
+ const socket = await deps.connect();
10
27
  const id = String(Date.now());
11
28
  socket.write(JSON.stringify({ id, action, ...payload }) + "\n");
12
29
  const line = await readLine(socket);
13
30
  socket.end();
14
31
  return JSON.parse(line);
15
32
  }
16
- async function ensureDaemon() {
17
- if (daemonAlive() && (await connect().then(ok, no)))
33
+ export async function ensureDaemon(deps) {
34
+ if (daemonAlive(deps) && (await deps.connect().then(ok, no)))
18
35
  return;
19
- const ext = import.meta.url.endsWith(".ts") ? ".ts" : ".js";
20
- const daemon = fileURLToPath(new URL(`./daemon${ext}`, import.meta.url));
21
- const child = spawn(process.execPath, [daemon], {
36
+ const child = deps.spawn(process.execPath, [deps.daemonPath], {
22
37
  detached: true,
23
38
  stdio: "ignore",
24
39
  });
25
40
  child.unref();
26
41
  for (let i = 0; i < 50; i++) {
27
- if (await connect().then(ok, no))
42
+ if (await deps.connect().then(ok, no))
28
43
  return;
29
- await sleep(100);
44
+ await deps.sleep(100);
30
45
  }
31
- throw new Error(`daemon failed to start (${socketPath})`);
46
+ throw new Error(`daemon failed to start (${deps.socketPath})`);
32
47
  }
33
- function daemonAlive() {
34
- if (!existsSync(pidFile))
48
+ export function daemonAlive(deps) {
49
+ if (!deps.existsSync(deps.pidFile))
35
50
  return false;
36
- const pid = Number(readFileSync(pidFile, "utf-8"));
51
+ const pid = Number(deps.readFileSync(deps.pidFile, "utf-8"));
37
52
  try {
38
- process.kill(pid, 0);
53
+ deps.processKill(pid, 0);
39
54
  return true;
40
55
  }
41
56
  catch {
42
- rmSync(pidFile, { force: true });
43
- removeSocketFile();
57
+ deps.rmSync(deps.pidFile, { force: true });
58
+ removeSocketFile(deps.socketPath, deps.rmSync);
44
59
  return false;
45
60
  }
46
61
  }
47
- function connect() {
62
+ export function connect() {
48
63
  return new Promise((resolve, reject) => {
49
64
  const socket = netConnect(socketPath);
50
65
  socket.once("connect", () => resolve(socket));
51
66
  socket.once("error", reject);
52
67
  });
53
68
  }
54
- function readLine(socket) {
69
+ export function readLine(socket) {
55
70
  return new Promise((resolve, reject) => {
56
71
  let buffer = "";
57
72
  socket.on("data", (chunk) => {
@@ -63,15 +78,15 @@ function readLine(socket) {
63
78
  socket.on("error", reject);
64
79
  });
65
80
  }
66
- function ok(s) {
81
+ export function ok(s) {
67
82
  s.destroy();
68
83
  return true;
69
84
  }
70
- function no() {
85
+ export function no() {
71
86
  return false;
72
87
  }
73
- function removeSocketFile() {
88
+ export function removeSocketFile(path, removeFile = rmSync) {
74
89
  if (process.platform === "win32")
75
90
  return;
76
- rmSync(socketPath, { force: true });
91
+ removeFile(path, { force: true });
77
92
  }
package/dist/daemon.d.ts CHANGED
@@ -1 +1,57 @@
1
- export {};
1
+ import type { Socket } from "node:net";
2
+ import * as browser from "./browser.js";
3
+ export type BrowserApi = typeof browser;
4
+ export type Cmd = {
5
+ action: string;
6
+ url?: string;
7
+ id?: string;
8
+ script?: string;
9
+ idx?: number;
10
+ mode?: "summary" | "trace" | "clear" | "snapshot";
11
+ limit?: number;
12
+ filter?: string;
13
+ mapped?: boolean;
14
+ inlineSource?: boolean;
15
+ cookies?: {
16
+ name: string;
17
+ value: string;
18
+ }[];
19
+ domain?: string;
20
+ store?: string;
21
+ };
22
+ export declare function cleanError(err: unknown): string;
23
+ export declare function createRunner(api?: BrowserApi): (cmd: Cmd) => Promise<{
24
+ ok: boolean;
25
+ data?: undefined;
26
+ error?: undefined;
27
+ } | {
28
+ ok: boolean;
29
+ data: number;
30
+ error?: undefined;
31
+ } | {
32
+ ok: boolean;
33
+ data: string;
34
+ error?: undefined;
35
+ } | {
36
+ ok: boolean;
37
+ error: string;
38
+ data?: undefined;
39
+ }>;
40
+ export declare function dispatchLine(line: string, socket: Pick<Socket, "write">, run?: (cmd: Cmd) => Promise<{
41
+ ok: boolean;
42
+ data?: undefined;
43
+ error?: undefined;
44
+ } | {
45
+ ok: boolean;
46
+ data: number;
47
+ error?: undefined;
48
+ } | {
49
+ ok: boolean;
50
+ data: string;
51
+ error?: undefined;
52
+ } | {
53
+ ok: boolean;
54
+ error: string;
55
+ data?: undefined;
56
+ }>, onClose?: () => void): Promise<void>;
57
+ export declare function startDaemon(): void;