@presto1314w/vite-devtools-browser 0.1.0 → 0.1.2
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 +118 -112
- package/dist/browser.js +68 -33
- package/dist/cli.js +12 -6
- package/dist/client.js +6 -1
- package/dist/daemon.js +8 -2
- package/dist/vue/devtools.js +61 -11
- package/package.json +11 -3
package/README.md
CHANGED
|
@@ -1,112 +1,118 @@
|
|
|
1
|
-
# vite-browser
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
vite-browser
|
|
27
|
-
vite-browser
|
|
28
|
-
vite-browser
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
-
|
|
43
|
-
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
vite-browser
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
vite-browser
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
vite-browser
|
|
73
|
-
vite-browser
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
###
|
|
77
|
-
```bash
|
|
78
|
-
vite-browser
|
|
79
|
-
vite-browser
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
###
|
|
83
|
-
```bash
|
|
84
|
-
vite-browser
|
|
85
|
-
vite-browser
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
-
|
|
95
|
-
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
-
|
|
102
|
-
-
|
|
103
|
-
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
1
|
+
# vite-browser
|
|
2
|
+
|
|
3
|
+
Agent Skill for AI coding assistants to debug Vite applications with structured access to Vue/React/Svelte runtime state. The CLI is the supporting runtime used by the skill for component trees, store/router inspection, logs, network traces, screenshots, and scripted page evaluation.
|
|
4
|
+
|
|
5
|
+
## Skills
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx skills add MapleCity1314/vite-browser
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## CLI Installation (Optional)
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g @presto1314w/vite-devtools-browser
|
|
15
|
+
npx playwright install chromium
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Start your Vite dev server
|
|
22
|
+
cd my-vue-app
|
|
23
|
+
npm run dev
|
|
24
|
+
|
|
25
|
+
# In another terminal
|
|
26
|
+
vite-browser open http://localhost:5173
|
|
27
|
+
vite-browser detect # vue@3.5.29 / react@19.x / svelte@x
|
|
28
|
+
vite-browser vue tree # Vue component tree
|
|
29
|
+
vite-browser react tree # React component tree
|
|
30
|
+
vite-browser svelte tree # Svelte component tree (best effort)
|
|
31
|
+
vite-browser screenshot # Take screenshot
|
|
32
|
+
vite-browser logs # Console logs
|
|
33
|
+
vite-browser network # Network requests
|
|
34
|
+
vite-browser close
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Features
|
|
38
|
+
|
|
39
|
+
- Framework Detection: Auto-detect Vue, React, Svelte and versions (best effort)
|
|
40
|
+
- Vue DevTools: Component tree, props, state, computed properties, source locations
|
|
41
|
+
- React DevTools: Component tree + component inspection (props/hooks/state/context)
|
|
42
|
+
- Svelte Support: Component tree + component detail inspection when runtime metadata is available
|
|
43
|
+
- Pinia Integration: Inspect store state and getters
|
|
44
|
+
- Vue Router: Current route, params, query, all routes
|
|
45
|
+
- Network Monitoring: Track requests, headers, bodies, and response payloads
|
|
46
|
+
- Console Logs: Capture console.log, warn, error, debug
|
|
47
|
+
- Screenshots: Full-page PNG screenshots
|
|
48
|
+
- JavaScript Evaluation: Run arbitrary JS in page context
|
|
49
|
+
- Vite Integration: Error tracking, HMR monitoring
|
|
50
|
+
|
|
51
|
+
## Commands
|
|
52
|
+
|
|
53
|
+
### Browser Control
|
|
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
|
+
```
|
|
61
|
+
|
|
62
|
+
### Framework Detection
|
|
63
|
+
```bash
|
|
64
|
+
vite-browser detect # Detect framework and version
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Vue DevTools
|
|
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
|
+
```
|
|
75
|
+
|
|
76
|
+
### React DevTools
|
|
77
|
+
```bash
|
|
78
|
+
vite-browser react tree # Show React component tree
|
|
79
|
+
vite-browser react tree <id> # Inspect props/hooks/state/context/source
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Svelte
|
|
83
|
+
```bash
|
|
84
|
+
vite-browser svelte tree # Show Svelte component tree
|
|
85
|
+
vite-browser svelte tree <id> # Inspect Svelte component details
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Debugging
|
|
89
|
+
```bash
|
|
90
|
+
vite-browser screenshot # Take full-page screenshot
|
|
91
|
+
vite-browser eval <script> # Run JavaScript in page
|
|
92
|
+
vite-browser logs # Show console logs
|
|
93
|
+
vite-browser errors # Show Vite errors
|
|
94
|
+
vite-browser network # List network requests
|
|
95
|
+
vite-browser network <idx> # Inspect specific request
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Architecture
|
|
99
|
+
|
|
100
|
+
- Daemon + Socket: Background process with socket communication
|
|
101
|
+
- Playwright: Headed Chromium browser
|
|
102
|
+
- One Browser, One Page: Single persistent browser instance
|
|
103
|
+
- Auto-start: Daemon starts automatically on first command
|
|
104
|
+
|
|
105
|
+
## Requirements
|
|
106
|
+
|
|
107
|
+
- Node.js 20+
|
|
108
|
+
- Chromium (via Playwright)
|
|
109
|
+
- Vite dev server running
|
|
110
|
+
- Vue/React/Svelte app for framework-specific commands
|
|
111
|
+
|
|
112
|
+
## Documentation
|
|
113
|
+
|
|
114
|
+
See [SKILL.md](./skills/SKILL.md) for complete command reference and usage examples.
|
|
115
|
+
|
|
116
|
+
## License
|
|
117
|
+
|
|
118
|
+
MIT
|
package/dist/browser.js
CHANGED
|
@@ -15,19 +15,12 @@ const installHook = hasReactExtension
|
|
|
15
15
|
let context = null;
|
|
16
16
|
let page = null;
|
|
17
17
|
let framework = "unknown";
|
|
18
|
+
let extensionModeDisabled = false;
|
|
18
19
|
const consoleLogs = [];
|
|
19
20
|
const MAX_LOGS = 200;
|
|
20
21
|
let lastReactSnapshot = [];
|
|
21
22
|
export async function open(url) {
|
|
22
|
-
|
|
23
|
-
context = await launch();
|
|
24
|
-
page = context.pages()[0] ?? (await context.newPage());
|
|
25
|
-
attachListeners(page);
|
|
26
|
-
networkLog.attach(page);
|
|
27
|
-
}
|
|
28
|
-
const currentPage = page;
|
|
29
|
-
if (!currentPage)
|
|
30
|
-
throw new Error("browser not open");
|
|
23
|
+
const currentPage = await ensurePage();
|
|
31
24
|
if (url) {
|
|
32
25
|
await currentPage.goto(url, { waitUntil: "domcontentloaded" });
|
|
33
26
|
await detectFramework();
|
|
@@ -48,20 +41,65 @@ export async function close() {
|
|
|
48
41
|
networkLog.clear();
|
|
49
42
|
lastReactSnapshot = [];
|
|
50
43
|
}
|
|
44
|
+
async function ensurePage() {
|
|
45
|
+
if (!contextUsable(context)) {
|
|
46
|
+
await close();
|
|
47
|
+
context = await launch();
|
|
48
|
+
}
|
|
49
|
+
if (!context)
|
|
50
|
+
throw new Error("browser not open");
|
|
51
|
+
if (!page || page.isClosed()) {
|
|
52
|
+
try {
|
|
53
|
+
page = context.pages()[0] ?? (await context.newPage());
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (!isClosedTargetError(error))
|
|
57
|
+
throw error;
|
|
58
|
+
await close();
|
|
59
|
+
extensionModeDisabled = true;
|
|
60
|
+
context = await launch();
|
|
61
|
+
page = context.pages()[0] ?? (await context.newPage());
|
|
62
|
+
}
|
|
63
|
+
attachListeners(page);
|
|
64
|
+
networkLog.attach(page);
|
|
65
|
+
}
|
|
66
|
+
return page;
|
|
67
|
+
}
|
|
68
|
+
function contextUsable(current) {
|
|
69
|
+
if (!current)
|
|
70
|
+
return false;
|
|
71
|
+
try {
|
|
72
|
+
current.pages();
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function isClosedTargetError(error) {
|
|
80
|
+
if (!(error instanceof Error))
|
|
81
|
+
return false;
|
|
82
|
+
return /Target page, context or browser has been closed/i.test(error.message);
|
|
83
|
+
}
|
|
51
84
|
async function launch() {
|
|
52
|
-
if (hasReactExtension && installHook) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
85
|
+
if (hasReactExtension && installHook && !extensionModeDisabled) {
|
|
86
|
+
try {
|
|
87
|
+
const ctx = await chromium.launchPersistentContext("", {
|
|
88
|
+
headless: false,
|
|
89
|
+
viewport: { width: 1280, height: 720 },
|
|
90
|
+
args: [
|
|
91
|
+
`--disable-extensions-except=${extensionPath}`,
|
|
92
|
+
`--load-extension=${extensionPath}`,
|
|
93
|
+
"--auto-open-devtools-for-tabs",
|
|
94
|
+
],
|
|
95
|
+
});
|
|
96
|
+
await ctx.waitForEvent("serviceworker").catch(() => { });
|
|
97
|
+
await ctx.addInitScript(installHook);
|
|
98
|
+
return ctx;
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
extensionModeDisabled = true;
|
|
102
|
+
}
|
|
65
103
|
}
|
|
66
104
|
const browser = await chromium.launch({
|
|
67
105
|
headless: false,
|
|
@@ -78,22 +116,19 @@ function attachListeners(currentPage) {
|
|
|
78
116
|
});
|
|
79
117
|
}
|
|
80
118
|
export async function goto(url) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
await page.goto(url, { waitUntil: "domcontentloaded" });
|
|
119
|
+
const currentPage = await ensurePage();
|
|
120
|
+
await currentPage.goto(url, { waitUntil: "domcontentloaded" });
|
|
84
121
|
await detectFramework();
|
|
85
|
-
return
|
|
122
|
+
return currentPage.url();
|
|
86
123
|
}
|
|
87
124
|
export async function back() {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
await page.goBack({ waitUntil: "domcontentloaded" });
|
|
125
|
+
const currentPage = await ensurePage();
|
|
126
|
+
await currentPage.goBack({ waitUntil: "domcontentloaded" });
|
|
91
127
|
}
|
|
92
128
|
export async function reload() {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return page.url();
|
|
129
|
+
const currentPage = await ensurePage();
|
|
130
|
+
await currentPage.reload({ waitUntil: "domcontentloaded" });
|
|
131
|
+
return currentPage.url();
|
|
97
132
|
}
|
|
98
133
|
export async function detectFramework() {
|
|
99
134
|
if (!page)
|
package/dist/cli.js
CHANGED
|
@@ -13,6 +13,7 @@ if (cmd === "open") {
|
|
|
13
13
|
console.error("usage: vite-browser open <url> [--cookies-json <file>]");
|
|
14
14
|
process.exit(1);
|
|
15
15
|
}
|
|
16
|
+
const url = normalizeUrl(arg);
|
|
16
17
|
const cookieIdx = args.indexOf("--cookies-json");
|
|
17
18
|
const cookieFile = cookieIdx >= 0 ? args[cookieIdx + 1] : undefined;
|
|
18
19
|
if (cookieFile) {
|
|
@@ -21,15 +22,15 @@ if (cmd === "open") {
|
|
|
21
22
|
exit(res, "");
|
|
22
23
|
const raw = readFileSync(cookieFile, "utf-8");
|
|
23
24
|
const cookies = JSON.parse(raw);
|
|
24
|
-
const domain = new URL(
|
|
25
|
+
const domain = new URL(url).hostname;
|
|
25
26
|
const cRes = await send("cookies", { cookies, domain });
|
|
26
27
|
if (!cRes.ok)
|
|
27
28
|
exit(cRes, "");
|
|
28
|
-
await send("goto", { url
|
|
29
|
-
exit(res, `opened -> ${
|
|
29
|
+
await send("goto", { url });
|
|
30
|
+
exit(res, `opened -> ${url} (${cookies.length} cookies for ${domain})`);
|
|
30
31
|
}
|
|
31
|
-
const res = await send("open", { url
|
|
32
|
-
exit(res, `opened -> ${
|
|
32
|
+
const res = await send("open", { url });
|
|
33
|
+
exit(res, `opened -> ${url}`);
|
|
33
34
|
}
|
|
34
35
|
if (cmd === "close") {
|
|
35
36
|
const res = await send("close");
|
|
@@ -40,7 +41,7 @@ if (cmd === "goto") {
|
|
|
40
41
|
console.error("usage: vite-browser goto <url>");
|
|
41
42
|
process.exit(1);
|
|
42
43
|
}
|
|
43
|
-
const res = await send("goto", { url: arg });
|
|
44
|
+
const res = await send("goto", { url: normalizeUrl(arg) });
|
|
44
45
|
exit(res, res.ok ? `-> ${res.data}` : "");
|
|
45
46
|
}
|
|
46
47
|
if (cmd === "back") {
|
|
@@ -166,3 +167,8 @@ OPTIONS
|
|
|
166
167
|
-h, --help Show this help message
|
|
167
168
|
`);
|
|
168
169
|
}
|
|
170
|
+
function normalizeUrl(value) {
|
|
171
|
+
if (value.includes("://"))
|
|
172
|
+
return value;
|
|
173
|
+
return `http://${value}`;
|
|
174
|
+
}
|
package/dist/client.js
CHANGED
|
@@ -40,7 +40,7 @@ function daemonAlive() {
|
|
|
40
40
|
}
|
|
41
41
|
catch {
|
|
42
42
|
rmSync(pidFile, { force: true });
|
|
43
|
-
|
|
43
|
+
removeSocketFile();
|
|
44
44
|
return false;
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -70,3 +70,8 @@ function ok(s) {
|
|
|
70
70
|
function no() {
|
|
71
71
|
return false;
|
|
72
72
|
}
|
|
73
|
+
function removeSocketFile() {
|
|
74
|
+
if (process.platform === "win32")
|
|
75
|
+
return;
|
|
76
|
+
rmSync(socketPath, { force: true });
|
|
77
|
+
}
|
package/dist/daemon.js
CHANGED
|
@@ -3,7 +3,7 @@ import { mkdirSync, writeFileSync, rmSync } from "node:fs";
|
|
|
3
3
|
import * as browser from "./browser.js";
|
|
4
4
|
import { socketDir, socketPath, pidFile } from "./paths.js";
|
|
5
5
|
mkdirSync(socketDir, { recursive: true, mode: 0o700 });
|
|
6
|
-
|
|
6
|
+
removeSocketFile();
|
|
7
7
|
rmSync(pidFile, { force: true });
|
|
8
8
|
writeFileSync(pidFile, String(process.pid));
|
|
9
9
|
const server = createServer((socket) => {
|
|
@@ -127,6 +127,12 @@ function shutdown() {
|
|
|
127
127
|
process.exit(0);
|
|
128
128
|
}
|
|
129
129
|
function cleanup() {
|
|
130
|
-
|
|
130
|
+
removeSocketFile();
|
|
131
131
|
rmSync(pidFile, { force: true });
|
|
132
132
|
}
|
|
133
|
+
function removeSocketFile() {
|
|
134
|
+
// Windows named pipes are not filesystem entries, so unlinking them fails with EPERM.
|
|
135
|
+
if (process.platform === "win32")
|
|
136
|
+
return;
|
|
137
|
+
rmSync(socketPath, { force: true });
|
|
138
|
+
}
|
package/dist/vue/devtools.js
CHANGED
|
@@ -176,12 +176,51 @@ export async function getComponentDetails(page, id) {
|
|
|
176
176
|
*/
|
|
177
177
|
export async function getPiniaStores(page, storeName) {
|
|
178
178
|
const result = await page.evaluate((name) => {
|
|
179
|
+
const safeJson = (value) => {
|
|
180
|
+
if (typeof value === "function")
|
|
181
|
+
return "[Function]";
|
|
182
|
+
if (typeof value === "bigint")
|
|
183
|
+
return value.toString();
|
|
184
|
+
const seen = new WeakSet();
|
|
185
|
+
try {
|
|
186
|
+
return JSON.stringify(value, (_, v) => {
|
|
187
|
+
if (typeof v === "function")
|
|
188
|
+
return "[Function]";
|
|
189
|
+
if (typeof v === "bigint")
|
|
190
|
+
return v.toString();
|
|
191
|
+
if (v && typeof v === "object") {
|
|
192
|
+
if (seen.has(v))
|
|
193
|
+
return "[Circular]";
|
|
194
|
+
seen.add(v);
|
|
195
|
+
}
|
|
196
|
+
return v;
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
return String(value);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
const hook = window.__VUE_DEVTOOLS_GLOBAL_HOOK__;
|
|
204
|
+
const piniaFromApp = hook?.apps?.[0]?.config?.globalProperties?.$pinia;
|
|
179
205
|
// Try to find Pinia instance
|
|
180
|
-
const pinia = window.__PINIA__ || window.pinia;
|
|
206
|
+
const pinia = window.__PINIA__ || window.pinia || piniaFromApp;
|
|
181
207
|
if (!pinia)
|
|
182
208
|
return "Pinia not found";
|
|
183
|
-
|
|
184
|
-
const
|
|
209
|
+
// Pinia v3 uses Map for _s, older integrations can expose plain objects.
|
|
210
|
+
const storesById = {};
|
|
211
|
+
const registry = pinia._s;
|
|
212
|
+
if (registry instanceof Map) {
|
|
213
|
+
registry.forEach((store, id) => {
|
|
214
|
+
storesById[String(id)] = store;
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
else if (registry && typeof registry === "object") {
|
|
218
|
+
for (const [id, store] of Object.entries(registry)) {
|
|
219
|
+
storesById[id] = store;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const stateById = pinia.state?.value && typeof pinia.state.value === "object" ? pinia.state.value : {};
|
|
223
|
+
const storeKeys = Array.from(new Set([...Object.keys(storesById), ...Object.keys(stateById)]));
|
|
185
224
|
if (storeKeys.length === 0)
|
|
186
225
|
return "No Pinia stores found";
|
|
187
226
|
const output = [];
|
|
@@ -195,29 +234,40 @@ export async function getPiniaStores(page, storeName) {
|
|
|
195
234
|
return output.join("\n");
|
|
196
235
|
}
|
|
197
236
|
// Get specific store
|
|
198
|
-
const store =
|
|
199
|
-
|
|
237
|
+
const store = storesById[name] ?? null;
|
|
238
|
+
const stateOnly = stateById[name];
|
|
239
|
+
if (!store && !stateOnly)
|
|
200
240
|
return `Store '${name}' not found`;
|
|
201
241
|
output.push(`# Pinia Store: ${name}\n`);
|
|
202
242
|
// State
|
|
203
|
-
const state = store
|
|
243
|
+
const state = store?.$state || store?.state || stateOnly || store;
|
|
204
244
|
if (state && typeof state === 'object') {
|
|
205
245
|
output.push("## State");
|
|
206
246
|
for (const [key, value] of Object.entries(state)) {
|
|
207
247
|
if (key.startsWith('$'))
|
|
208
248
|
continue; // Skip Pinia internals
|
|
209
|
-
output.push(` ${key}: ${
|
|
249
|
+
output.push(` ${key}: ${safeJson(value)}`);
|
|
210
250
|
}
|
|
211
251
|
output.push("");
|
|
212
252
|
}
|
|
213
253
|
// Getters
|
|
214
|
-
const
|
|
215
|
-
|
|
254
|
+
const getterNames = [];
|
|
255
|
+
const rawGetters = store?._getters;
|
|
256
|
+
if (Array.isArray(rawGetters)) {
|
|
257
|
+
getterNames.push(...rawGetters.map((g) => String(g)));
|
|
258
|
+
}
|
|
259
|
+
else if (rawGetters instanceof Set) {
|
|
260
|
+
getterNames.push(...Array.from(rawGetters).map((g) => String(g)));
|
|
261
|
+
}
|
|
262
|
+
else if (rawGetters && typeof rawGetters === "object") {
|
|
263
|
+
getterNames.push(...Object.keys(rawGetters));
|
|
264
|
+
}
|
|
265
|
+
if (getterNames.length > 0) {
|
|
216
266
|
output.push("## Getters");
|
|
217
|
-
for (const key of
|
|
267
|
+
for (const key of getterNames) {
|
|
218
268
|
try {
|
|
219
269
|
const value = store[key];
|
|
220
|
-
output.push(` ${key}: ${
|
|
270
|
+
output.push(` ${key}: ${safeJson(value)}`);
|
|
221
271
|
}
|
|
222
272
|
catch {
|
|
223
273
|
output.push(` ${key}: [Error]`);
|
package/package.json
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@presto1314w/vite-devtools-browser",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "CLI for programmatic access to Vue/React DevTools in Vite applications",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/MapleCity1314/vite-browser.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/MapleCity1314/vite-browser#readme",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/MapleCity1314/vite-browser/issues"
|
|
13
|
+
},
|
|
6
14
|
"type": "module",
|
|
7
15
|
"engines": {
|
|
8
16
|
"node": ">=20"
|
|
@@ -11,10 +19,10 @@
|
|
|
11
19
|
"dist"
|
|
12
20
|
],
|
|
13
21
|
"bin": {
|
|
14
|
-
"vite-browser": "
|
|
22
|
+
"vite-browser": "dist/cli.js"
|
|
15
23
|
},
|
|
16
24
|
"scripts": {
|
|
17
|
-
"start": "node --
|
|
25
|
+
"start": "node --import tsx src/cli.ts",
|
|
18
26
|
"dev": "tsx src/cli.ts",
|
|
19
27
|
"typecheck": "tsc --noEmit",
|
|
20
28
|
"build": "tsc -p tsconfig.build.json",
|