@vitejs/devtools 0.0.0-alpha.17 → 0.0.0-alpha.19

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.
@@ -1,13 +1,14 @@
1
1
  import { n as dirDist, t as dirClientStandalone } from "./dirs-DcSK9l9L.js";
2
2
  import Debug from "debug";
3
- import { toDataURL } from "mlly";
4
3
  import { debounce } from "perfect-debounce";
4
+ import { toDataURL } from "mlly";
5
+ import { createEventEmitter } from "@vitejs/devtools-kit/utils/events";
5
6
  import { RpcFunctionsCollectorBase } from "birpc-x";
7
+ import process$1 from "node:process";
6
8
  import { existsSync } from "node:fs";
7
9
  import sirv from "sirv";
8
10
  import { defineRpcFunction } from "@vitejs/devtools-kit";
9
11
  import { join } from "node:path";
10
- import process$1 from "node:process";
11
12
  import { normalizePath } from "vite";
12
13
  import { createRpcServer } from "@vitejs/devtools-rpc";
13
14
  import { createWsRpcPreset } from "@vitejs/devtools-rpc/presets/ws/server";
@@ -53,12 +54,9 @@ const ContextUtils = { createSimpleClientScript(fn) {
53
54
  //#region src/node/host-docks.ts
54
55
  var DevToolsDockHost = class {
55
56
  views = /* @__PURE__ */ new Map();
56
- _sendOnChange;
57
+ events = createEventEmitter();
57
58
  constructor(context) {
58
59
  this.context = context;
59
- this._sendOnChange = debounce(() => {
60
- context.rpc.boardcast?.$callOptional("vite:core:list-dock-entries:updated");
61
- }, 10);
62
60
  }
63
61
  values() {
64
62
  return Array.from(this.views.values());
@@ -66,12 +64,16 @@ var DevToolsDockHost = class {
66
64
  register(view, force) {
67
65
  if (this.views.has(view.id) && !force) throw new Error(`Dock with id "${view.id}" is already registered`);
68
66
  this.views.set(view.id, view);
69
- this._sendOnChange();
67
+ this.events.emit("dock:entry:updated", view);
68
+ return { update: (patch) => {
69
+ if (patch.id && patch.id !== view.id) throw new Error(`Cannot change the id of a dock. Use register() to add new docks.`);
70
+ this.update(Object.assign(this.views.get(view.id), patch));
71
+ } };
70
72
  }
71
73
  update(view) {
72
74
  if (!this.views.has(view.id)) throw new Error(`Dock with id "${view.id}" is not registered. Use register() to add new docks.`);
73
75
  this.views.set(view.id, view);
74
- this._sendOnChange();
76
+ this.events.emit("dock:entry:updated", view);
75
77
  }
76
78
  };
77
79
 
@@ -84,6 +86,104 @@ var RpcFunctionsHost = class extends RpcFunctionsCollectorBase {
84
86
  }
85
87
  };
86
88
 
89
+ //#endregion
90
+ //#region src/node/host-terminals.ts
91
+ var DevToolsTerminalHost = class {
92
+ sessions = /* @__PURE__ */ new Map();
93
+ events = createEventEmitter();
94
+ _boundStreams = /* @__PURE__ */ new Map();
95
+ constructor(context) {
96
+ this.context = context;
97
+ }
98
+ register(session) {
99
+ if (this.sessions.has(session.id)) throw new Error(`Terminal session with id "${session.id}" already registered`);
100
+ this.sessions.set(session.id, session);
101
+ this.bindStream(session);
102
+ this.events.emit("terminal:session:updated", session);
103
+ return session;
104
+ }
105
+ update(patch) {
106
+ if (!this.sessions.has(patch.id)) throw new Error(`Terminal session with id "${patch.id}" not registered`);
107
+ const session = this.sessions.get(patch.id);
108
+ Object.assign(session, patch);
109
+ this.sessions.set(patch.id, session);
110
+ this.bindStream(session);
111
+ this.events.emit("terminal:session:updated", session);
112
+ }
113
+ remove(session) {
114
+ this.sessions.delete(session.id);
115
+ this.events.emit("terminal:session:updated", session);
116
+ this._boundStreams.delete(session.id);
117
+ }
118
+ bindStream(session) {
119
+ if (this._boundStreams.has(session.id) && this._boundStreams.get(session.id)?.stream === session.stream) return;
120
+ this._boundStreams.get(session.id)?.dispose();
121
+ this._boundStreams.delete(session.id);
122
+ if (!session.stream) return;
123
+ session.buffer ||= [];
124
+ const events = this.events;
125
+ const writer = new WritableStream({ write(chunk) {
126
+ session.buffer.push(chunk);
127
+ events.emit("terminal:session:stream-chunk", {
128
+ id: session.id,
129
+ chunks: [chunk],
130
+ ts: Date.now()
131
+ });
132
+ } });
133
+ session.stream.pipeTo(writer);
134
+ this._boundStreams.set(session.id, {
135
+ dispose: () => {
136
+ writer.close();
137
+ },
138
+ stream: session.stream
139
+ });
140
+ }
141
+ async startChildProcess(executeOptions, terminal) {
142
+ if (this.sessions.has(terminal.id)) throw new Error(`Terminal session with id "${terminal.id}" already registered`);
143
+ const { exec } = await import("tinyexec");
144
+ let controller;
145
+ const stream = new ReadableStream({ start(_controller) {
146
+ controller = _controller;
147
+ } });
148
+ function createChildProcess() {
149
+ const cp$1 = exec(executeOptions.command, executeOptions.args || [], { nodeOptions: {
150
+ env: {
151
+ COLORS: "true",
152
+ FORCE_COLOR: "true",
153
+ ...executeOptions.env || {}
154
+ },
155
+ cwd: executeOptions.cwd ?? process$1.cwd(),
156
+ stdio: "pipe"
157
+ } });
158
+ (async () => {
159
+ for await (const chunk of cp$1) controller?.enqueue(chunk);
160
+ })();
161
+ return cp$1;
162
+ }
163
+ let cp = createChildProcess();
164
+ const restart = async () => {
165
+ cp?.kill();
166
+ cp = createChildProcess();
167
+ };
168
+ const terminate = async () => {
169
+ cp?.kill();
170
+ cp = void 0;
171
+ };
172
+ const session = {
173
+ ...terminal,
174
+ status: "running",
175
+ stream,
176
+ type: "child-process",
177
+ executeOptions,
178
+ getChildProcess: () => cp?.process,
179
+ terminate,
180
+ restart
181
+ };
182
+ this.register(session);
183
+ return Promise.resolve(session);
184
+ }
185
+ };
186
+
87
187
  //#endregion
88
188
  //#region src/node/host-views.ts
89
189
  var DevToolsViewHost = class {
@@ -111,20 +211,76 @@ var DevToolsViewHost = class {
111
211
  };
112
212
 
113
213
  //#endregion
114
- //#region src/node/rpc/list-dock-entries.ts
115
- const listDockEntries = defineRpcFunction({
116
- name: "vite:core:list-dock-entries",
117
- type: "query",
214
+ //#region src/node/rpc/internal/docks-list.ts
215
+ const docksList = defineRpcFunction({
216
+ name: "vite:internal:docks:list",
217
+ type: "static",
118
218
  setup: (context) => {
119
- return { handler: () => Array.from(context.docks.values()) };
219
+ const builtinDocksEntries = [{
220
+ type: "~builtin",
221
+ id: "~terminals",
222
+ title: "Terminals",
223
+ icon: "ph:terminal-duotone",
224
+ get isHidden() {
225
+ return context.terminals.sessions.size === 0;
226
+ }
227
+ }];
228
+ return { handler: () => [...Array.from(context.docks.values()), ...builtinDocksEntries] };
120
229
  }
121
230
  });
122
231
 
123
232
  //#endregion
124
- //#region src/node/rpc/list-rpc-functions.ts
125
- const listRpcFunctions = defineRpcFunction({
126
- name: "vite:core:list-rpc-functions",
233
+ //#region src/node/rpc/internal/docks-on-launch.ts
234
+ const docksOnLaunch = defineRpcFunction({
235
+ name: "vite:internal:docks:on-launch",
127
236
  type: "action",
237
+ setup: (context) => {
238
+ const launchMap = /* @__PURE__ */ new Map();
239
+ return { handler: async (entryId) => {
240
+ if (launchMap.has(entryId)) return launchMap.get(entryId);
241
+ const entry = context.docks.values().find((entry$1) => entry$1.id === entryId);
242
+ if (!entry) throw new Error(`Dock entry with id "${entryId}" not found`);
243
+ if (entry.type !== "launcher") throw new Error(`Dock entry with id "${entryId}" is not a launcher`);
244
+ try {
245
+ context.docks.update({
246
+ ...entry,
247
+ launcher: {
248
+ ...entry.launcher,
249
+ status: "loading"
250
+ }
251
+ });
252
+ const promise = entry.launcher.onLaunch();
253
+ launchMap.set(entryId, promise);
254
+ const result = await promise;
255
+ const newEntry = context.docks.values().find((entry$1) => entry$1.id === entryId) || entry;
256
+ if (newEntry.type === "launcher") context.docks.update({
257
+ ...newEntry,
258
+ launcher: {
259
+ ...newEntry.launcher,
260
+ status: "success"
261
+ }
262
+ });
263
+ return result;
264
+ } catch (error) {
265
+ console.error(`[VITE DEVTOOLS] Error launching dock entry "${entryId}"`, error);
266
+ context.docks.update({
267
+ ...entry,
268
+ launcher: {
269
+ ...entry.launcher,
270
+ status: "error",
271
+ error: error instanceof Error ? error.message : String(error)
272
+ }
273
+ });
274
+ }
275
+ } };
276
+ }
277
+ });
278
+
279
+ //#endregion
280
+ //#region src/node/rpc/internal/rpc-server-list.ts
281
+ const rpcServerList = defineRpcFunction({
282
+ name: "vite:internal:rpc:server:list",
283
+ type: "static",
128
284
  setup: (context) => {
129
285
  return { async handler() {
130
286
  return Object.fromEntries(Array.from(context.rpc.definitions.entries()).map(([name, fn]) => [name, { type: fn.type }]));
@@ -133,7 +289,43 @@ const listRpcFunctions = defineRpcFunction({
133
289
  });
134
290
 
135
291
  //#endregion
136
- //#region src/node/rpc/open-in-editor.ts
292
+ //#region src/node/rpc/internal/terminals-list.ts
293
+ const terminalsList = defineRpcFunction({
294
+ name: "vite:internal:terminals:list",
295
+ type: "static",
296
+ setup: (context) => {
297
+ return { async handler() {
298
+ return Array.from(context.terminals.sessions.values()).map((i$1) => {
299
+ return {
300
+ id: i$1.id,
301
+ title: i$1.title,
302
+ description: i$1.description,
303
+ status: i$1.status
304
+ };
305
+ });
306
+ } };
307
+ }
308
+ });
309
+
310
+ //#endregion
311
+ //#region src/node/rpc/internal/terminals-read.ts
312
+ const terminalsRead = defineRpcFunction({
313
+ name: "vite:internal:terminals:read",
314
+ type: "query",
315
+ setup: (context) => {
316
+ return { async handler(id) {
317
+ const seesion = context.terminals.sessions.get(id);
318
+ if (!seesion) throw new Error(`Terminal session with id "${id}" not found`);
319
+ return {
320
+ buffer: seesion.buffer ?? [],
321
+ ts: Date.now()
322
+ };
323
+ } };
324
+ }
325
+ });
326
+
327
+ //#endregion
328
+ //#region src/node/rpc/public/open-in-editor.ts
137
329
  const openInEditor = defineRpcFunction({
138
330
  name: "vite:core:open-in-editor",
139
331
  type: "action",
@@ -145,7 +337,7 @@ const openInEditor = defineRpcFunction({
145
337
  });
146
338
 
147
339
  //#endregion
148
- //#region src/node/rpc/open-in-finder.ts
340
+ //#region src/node/rpc/public/open-in-finder.ts
149
341
  const openInFinder = defineRpcFunction({
150
342
  name: "vite:core:open-in-finder",
151
343
  type: "action",
@@ -158,12 +350,15 @@ const openInFinder = defineRpcFunction({
158
350
 
159
351
  //#endregion
160
352
  //#region src/node/rpc/index.ts
161
- const builtinRpcFunctions = [
162
- listRpcFunctions,
163
- listDockEntries,
164
- openInEditor,
165
- openInFinder
353
+ const builtinPublicRpcDecalrations = [openInEditor, openInFinder];
354
+ const builtinInternalRpcDecalrations = [
355
+ docksList,
356
+ docksOnLaunch,
357
+ rpcServerList,
358
+ terminalsList,
359
+ terminalsRead
166
360
  ];
361
+ const builtinRpcDecalrations = [...builtinPublicRpcDecalrations, ...builtinInternalRpcDecalrations];
167
362
 
168
363
  //#endregion
169
364
  //#region src/node/context.ts
@@ -177,15 +372,28 @@ async function createDevToolsContext(viteConfig, viteServer) {
177
372
  rpc: void 0,
178
373
  docks: void 0,
179
374
  views: void 0,
180
- utils: ContextUtils
375
+ utils: ContextUtils,
376
+ terminals: void 0
181
377
  };
182
378
  const rpcHost = new RpcFunctionsHost(context);
183
379
  const docksHost = new DevToolsDockHost(context);
184
380
  const viewsHost = new DevToolsViewHost(context);
381
+ const terminalsHost = new DevToolsTerminalHost(context);
185
382
  context.rpc = rpcHost;
186
383
  context.docks = docksHost;
187
384
  context.views = viewsHost;
188
- for (const fn of builtinRpcFunctions) rpcHost.register(fn);
385
+ context.terminals = terminalsHost;
386
+ for (const fn of builtinRpcDecalrations) rpcHost.register(fn);
387
+ docksHost.events.on("dock:entry:updated", debounce(() => {
388
+ rpcHost.boardcast.$callOptional("vite:internal:docks:updated");
389
+ }, 10));
390
+ terminalsHost.events.on("terminal:session:updated", debounce(() => {
391
+ rpcHost.boardcast.$callOptional("vite:internal:terminals:updated");
392
+ rpcHost.boardcast.$callOptional("vite:internal:docks:updated");
393
+ }, 10));
394
+ terminalsHost.events.on("terminal:session:stream-chunk", (data) => {
395
+ rpcHost.boardcast.$callOptional("vite:internal:terminals:stream-chunk", data);
396
+ });
189
397
  const plugins = viteConfig.plugins.filter((plugin) => "devtools" in plugin);
190
398
  for (const plugin of plugins) {
191
399
  if (!plugin.devtools?.setup) continue;
@@ -1275,20 +1483,21 @@ async function createWsServer(options) {
1275
1483
  //#endregion
1276
1484
  //#region src/node/server.ts
1277
1485
  async function createDevToolsMiddleware(options) {
1278
- const app = createApp();
1279
- const { rpc, getConnectionMeta: getMetadata } = await createWsServer(options);
1280
- app.use("/.vdt-connection.json", eventHandler(async (event) => {
1486
+ const h3 = createApp();
1487
+ const { rpc, getConnectionMeta } = await createWsServer(options);
1488
+ h3.use("/.vdt-connection.json", eventHandler(async (event) => {
1281
1489
  event.node.res.setHeader("Content-Type", "application/json");
1282
- return event.node.res.end(JSON.stringify(await getMetadata()));
1490
+ return event.node.res.end(JSON.stringify(await getConnectionMeta()));
1283
1491
  }));
1284
- app.use(fromNodeMiddleware(sirv(dirClientStandalone, {
1492
+ h3.use(fromNodeMiddleware(sirv(dirClientStandalone, {
1285
1493
  dev: true,
1286
1494
  single: true
1287
1495
  })));
1288
1496
  return {
1289
- h3: app,
1290
- middleware: toNodeListener(app),
1291
- rpc
1497
+ h3,
1498
+ rpc,
1499
+ middleware: toNodeListener(h3),
1500
+ getConnectionMeta
1292
1501
  };
1293
1502
  }
1294
1503
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitejs/devtools",
3
3
  "type": "module",
4
- "version": "0.0.0-alpha.17",
4
+ "version": "0.0.0-alpha.19",
5
5
  "description": "Vite DevTools",
6
6
  "author": "VoidZero Inc.",
7
7
  "license": "MIT",
@@ -47,26 +47,28 @@
47
47
  "debug": "^4.4.3",
48
48
  "launch-editor": "^2.12.0",
49
49
  "mlly": "^1.8.0",
50
- "nanoevents": "^9.1.0",
51
- "open": "^10.2.0",
50
+ "open": "^11.0.0",
52
51
  "pathe": "^2.0.3",
53
52
  "perfect-debounce": "^2.0.0",
54
53
  "sirv": "^3.0.2",
54
+ "tinyexec": "^1.0.2",
55
55
  "ws": "^8.18.3",
56
- "@vitejs/devtools-rpc": "0.0.0-alpha.17",
57
- "@vitejs/devtools-kit": "0.0.0-alpha.17",
58
- "@vitejs/devtools-vite": "0.0.0-alpha.17"
56
+ "@vitejs/devtools-rpc": "0.0.0-alpha.19",
57
+ "@vitejs/devtools-kit": "0.0.0-alpha.19",
58
+ "@vitejs/devtools-vite": "0.0.0-alpha.19"
59
59
  },
60
60
  "devDependencies": {
61
- "@vitejs/plugin-vue": "^6.0.1",
61
+ "@vitejs/plugin-vue": "^6.0.2",
62
+ "@xterm/addon-fit": "^0.10.0",
63
+ "@xterm/xterm": "^5.5.0",
62
64
  "tsdown": "^0.16.1",
63
65
  "typescript": "^5.9.3",
64
- "unplugin-vue": "^7.0.4",
66
+ "unplugin-vue": "^7.0.8",
65
67
  "vite": "npm:rolldown-vite@^7.2.2",
66
- "vue": "^3.5.24",
67
- "vue-tsc": "^3.1.3",
68
- "@vitejs/devtools-vite": "0.0.0-alpha.17",
69
- "@vitejs/devtools": "0.0.0-alpha.17"
68
+ "vue": "^3.5.25",
69
+ "vue-tsc": "^3.1.5",
70
+ "@vitejs/devtools-vite": "0.0.0-alpha.19",
71
+ "@vitejs/devtools": "0.0.0-alpha.19"
70
72
  },
71
73
  "scripts": {
72
74
  "build": "pnpm build:js && pnpm build:standalone",
@@ -75,7 +77,7 @@
75
77
  "watch": "tsdown --watch --config-loader=tsx",
76
78
  "dev:standalone": "cd src/client/standalone && vite dev",
77
79
  "play": "DEBUG='vite:devtools:*' pnpm -C playground run dev",
78
- "play:standlone": "DEBUG='vite:devtools:*' pnpm -C playground run dev:standalone",
80
+ "play:standalone": "DEBUG='vite:devtools:*' pnpm -C playground run dev:standalone",
79
81
  "cli": "DEBUG='vite:devtools:*' tsx src/node/cli.ts",
80
82
  "play:build": "pnpm -C playground run build"
81
83
  }