@vitejs/devtools-kit 0.0.0-alpha.3 → 0.0.0-alpha.31
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/client-script-BOHKZVPh.d.mts +1864 -0
- package/dist/client.d.mts +2 -0
- package/dist/client.mjs +1302 -0
- package/dist/constants.d.mts +7 -0
- package/dist/constants.mjs +20 -0
- package/dist/events-57bKw4ct.d.mts +71 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.mjs +7 -0
- package/dist/utils/events.d.mts +9 -0
- package/dist/utils/events.mjs +41 -0
- package/dist/utils/nanoid.d.mts +4 -0
- package/dist/utils/nanoid.mjs +11 -0
- package/dist/utils/shared-state.d.mts +53 -0
- package/dist/utils/shared-state.mjs +38 -0
- package/package.json +18 -13
- package/skills/vite-devtools-kit/SKILL.md +325 -0
- package/skills/vite-devtools-kit/references/dock-entry-types.md +240 -0
- package/skills/vite-devtools-kit/references/project-structure.md +247 -0
- package/skills/vite-devtools-kit/references/rpc-patterns.md +185 -0
- package/skills/vite-devtools-kit/references/shared-state-patterns.md +290 -0
- package/dist/client.d.ts +0 -17
- package/dist/client.js +0 -38
- package/dist/index.d.ts +0 -18
- package/dist/index.js +0 -17
- package/dist/rpc-ls6mUIa2.d.ts +0 -118
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { C as DevToolsDocksUserSettings } from "./client-script-BOHKZVPh.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/constants.d.ts
|
|
4
|
+
declare const DEFAULT_CATEGORIES_ORDER: Record<string, number>;
|
|
5
|
+
declare const DEFAULT_STATE_USER_SETTINGS: () => DevToolsDocksUserSettings;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { DEFAULT_CATEGORIES_ORDER, DEFAULT_STATE_USER_SETTINGS };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/constants.ts
|
|
2
|
+
const DEFAULT_CATEGORIES_ORDER = {
|
|
3
|
+
"~viteplus": -1e3,
|
|
4
|
+
"default": 0,
|
|
5
|
+
"app": 100,
|
|
6
|
+
"framework": 200,
|
|
7
|
+
"web": 300,
|
|
8
|
+
"advanced": 400,
|
|
9
|
+
"~builtin": 1e3
|
|
10
|
+
};
|
|
11
|
+
const DEFAULT_STATE_USER_SETTINGS = () => ({
|
|
12
|
+
docksHidden: [],
|
|
13
|
+
docksCategoriesHidden: [],
|
|
14
|
+
docksPinned: [],
|
|
15
|
+
docksCustomOrder: {},
|
|
16
|
+
showIframeAddressBar: false
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
export { DEFAULT_CATEGORIES_ORDER, DEFAULT_STATE_USER_SETTINGS };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
//#region src/types/events.d.ts
|
|
2
|
+
interface EventsMap {
|
|
3
|
+
[event: string]: any;
|
|
4
|
+
}
|
|
5
|
+
interface EventUnsubscribe {
|
|
6
|
+
(): void;
|
|
7
|
+
}
|
|
8
|
+
interface EventEmitter<Events extends EventsMap> {
|
|
9
|
+
/**
|
|
10
|
+
* Calls each of the listeners registered for a given event.
|
|
11
|
+
*
|
|
12
|
+
* ```js
|
|
13
|
+
* ee.emit('tick', tickType, tickDuration)
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @param event The event name.
|
|
17
|
+
* @param args The arguments for listeners.
|
|
18
|
+
*/
|
|
19
|
+
emit: <K extends keyof Events>(event: K, ...args: Parameters<Events[K]>) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Calls the listeners for a given event once and then removes the listener.
|
|
22
|
+
*
|
|
23
|
+
* @param event The event name.
|
|
24
|
+
* @param args The arguments for listeners.
|
|
25
|
+
*/
|
|
26
|
+
emitOnce: <K extends keyof Events>(event: K, ...args: Parameters<Events[K]>) => void;
|
|
27
|
+
/**
|
|
28
|
+
* Event names in keys and arrays with listeners in values.
|
|
29
|
+
*
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
_listeners: Partial<{ [E in keyof Events]: Events[E][] }>;
|
|
33
|
+
/**
|
|
34
|
+
* Add a listener for a given event.
|
|
35
|
+
*
|
|
36
|
+
* ```js
|
|
37
|
+
* const unbind = ee.on('tick', (tickType, tickDuration) => {
|
|
38
|
+
* count += 1
|
|
39
|
+
* })
|
|
40
|
+
*
|
|
41
|
+
* disable () {
|
|
42
|
+
* unbind()
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @param event The event name.
|
|
47
|
+
* @param cb The listener function.
|
|
48
|
+
* @returns Unbind listener from event.
|
|
49
|
+
*/
|
|
50
|
+
on: <K extends keyof Events>(event: K, cb: Events[K]) => EventUnsubscribe;
|
|
51
|
+
/**
|
|
52
|
+
* Add a listener for a given event once.
|
|
53
|
+
*
|
|
54
|
+
* ```js
|
|
55
|
+
* const unbind = ee.once('tick', (tickType, tickDuration) => {
|
|
56
|
+
* count += 1
|
|
57
|
+
* })
|
|
58
|
+
*
|
|
59
|
+
* disable () {
|
|
60
|
+
* unbind()
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @param event The event name.
|
|
65
|
+
* @param cb The listener function.
|
|
66
|
+
* @returns Unbind listener from event.
|
|
67
|
+
*/
|
|
68
|
+
once: <K extends keyof Events>(event: K, cb: Events[K]) => EventUnsubscribe;
|
|
69
|
+
}
|
|
70
|
+
//#endregion
|
|
71
|
+
export { EventUnsubscribe as n, EventsMap as r, EventEmitter as t };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { $ as DevToolsViewAction, A as ConnectionMeta, B as DevToolsTerminalSessionBase, C as DevToolsDocksUserSettings, D as RpcFunctionsHost, E as RpcBroadcastOptions, F as DevToolsViewHost, G as DevToolsRpcSharedStates, H as DevToolsTerminalStatus, I as DevToolsChildProcessExecuteOptions, J as DevToolsDockEntryBase, K as ClientScriptEntry, L as DevToolsChildProcessTerminalSession, M as DevToolsNodeContext, N as DevToolsNodeUtils, O as RpcSharedStateGetOptions, P as DevToolsPluginOptions, Q as DevToolsDockUserEntry, R as DevToolsTerminalHost, S as Thenable, T as DevToolsNodeRpcSessionMeta, U as DevToolsRpcClientFunctions, V as DevToolsTerminalSessionStreamChunkEvent, W as DevToolsRpcServerFunctions, X as DevToolsDockEntryIcon, Y as DevToolsDockEntryCategory, Z as DevToolsDockHost, _ as RpcDefinitionsToFunctions, b as EntriesToObject, et as DevToolsViewBuiltin, g as RpcDefinitionsFilter, h as defineRpcFunction, it as DevToolsViewLauncherStatus, j as DevToolsCapabilities, k as RpcSharedStateHost, nt as DevToolsViewIframe, q as DevToolsDockEntry, rt as DevToolsViewLauncher, tt as DevToolsViewCustomRender, v as PluginWithDevTools, w as DevToolsNodeRpcSession, x as PartialWithoutId, y as ViteConfigDevtoolsOptions, z as DevToolsTerminalSession } from "./client-script-BOHKZVPh.mjs";
|
|
2
|
+
import { n as EventUnsubscribe, r as EventsMap, t as EventEmitter } from "./events-57bKw4ct.mjs";
|
|
3
|
+
export { ClientScriptEntry, ConnectionMeta, DevToolsCapabilities, DevToolsChildProcessExecuteOptions, DevToolsChildProcessTerminalSession, DevToolsDockEntry, DevToolsDockEntryBase, DevToolsDockEntryCategory, DevToolsDockEntryIcon, DevToolsDockHost, DevToolsDockUserEntry, DevToolsDocksUserSettings, DevToolsNodeContext, DevToolsNodeRpcSession, DevToolsNodeRpcSessionMeta, DevToolsNodeUtils, DevToolsPluginOptions, DevToolsRpcClientFunctions, DevToolsRpcServerFunctions, DevToolsRpcSharedStates, DevToolsTerminalHost, DevToolsTerminalSession, DevToolsTerminalSessionBase, DevToolsTerminalSessionStreamChunkEvent, DevToolsTerminalStatus, DevToolsViewAction, DevToolsViewBuiltin, DevToolsViewCustomRender, DevToolsViewHost, DevToolsViewIframe, DevToolsViewLauncher, DevToolsViewLauncherStatus, EntriesToObject, EventEmitter, EventUnsubscribe, EventsMap, PartialWithoutId, PluginWithDevTools, RpcBroadcastOptions, RpcDefinitionsFilter, RpcDefinitionsToFunctions, RpcFunctionsHost, RpcSharedStateGetOptions, RpcSharedStateHost, Thenable, ViteConfigDevtoolsOptions, defineRpcFunction };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { r as EventsMap, t as EventEmitter } from "../events-57bKw4ct.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/utils/events.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Create event emitter.
|
|
6
|
+
*/
|
|
7
|
+
declare function createEventEmitter<Events extends EventsMap>(): EventEmitter<Events>;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { createEventEmitter };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region src/utils/events.ts
|
|
2
|
+
/**
|
|
3
|
+
* Create event emitter.
|
|
4
|
+
*/
|
|
5
|
+
function createEventEmitter() {
|
|
6
|
+
const _listeners = {};
|
|
7
|
+
function emit(event, ...args) {
|
|
8
|
+
const callbacks = _listeners[event] || [];
|
|
9
|
+
for (let i = 0, length = callbacks.length; i < length; i++) {
|
|
10
|
+
const callback = callbacks[i];
|
|
11
|
+
if (callback) callback(...args);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function emitOnce(event, ...args) {
|
|
15
|
+
emit(event, ...args);
|
|
16
|
+
delete _listeners[event];
|
|
17
|
+
}
|
|
18
|
+
function on(event, cb) {
|
|
19
|
+
(_listeners[event] ||= []).push(cb);
|
|
20
|
+
return () => {
|
|
21
|
+
_listeners[event] = _listeners[event]?.filter((i) => cb !== i);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function once(event, cb) {
|
|
25
|
+
const unsubscribe = on(event, ((...args) => {
|
|
26
|
+
unsubscribe();
|
|
27
|
+
return cb(...args);
|
|
28
|
+
}));
|
|
29
|
+
return unsubscribe;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
_listeners,
|
|
33
|
+
emit,
|
|
34
|
+
emitOnce,
|
|
35
|
+
on,
|
|
36
|
+
once
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//#endregion
|
|
41
|
+
export { createEventEmitter };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/utils/nanoid.ts
|
|
2
|
+
const urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
|
|
3
|
+
function nanoid(size = 21) {
|
|
4
|
+
let id = "";
|
|
5
|
+
let i = size;
|
|
6
|
+
while (i--) id += urlAlphabet[Math.random() * 64 | 0];
|
|
7
|
+
return id;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
export { nanoid };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { t as EventEmitter } from "../events-57bKw4ct.mjs";
|
|
2
|
+
import { Objectish, Patch, Patch as SharedStatePatch } from "immer";
|
|
3
|
+
|
|
4
|
+
//#region src/utils/shared-state.d.ts
|
|
5
|
+
type ImmutablePrimitive = undefined | null | boolean | string | number | Function;
|
|
6
|
+
type Immutable<T> = T extends ImmutablePrimitive ? T : T extends Array<infer U> ? ImmutableArray<U> : T extends Map<infer K, infer V> ? ImmutableMap<K, V> : T extends Set<infer M> ? ImmutableSet<M> : ImmutableObject<T>;
|
|
7
|
+
type ImmutableArray<T> = ReadonlyArray<Immutable<T>>;
|
|
8
|
+
type ImmutableMap<K, V> = ReadonlyMap<Immutable<K>, Immutable<V>>;
|
|
9
|
+
type ImmutableSet<T> = ReadonlySet<Immutable<T>>;
|
|
10
|
+
type ImmutableObject<T> = { readonly [K in keyof T]: Immutable<T[K]> };
|
|
11
|
+
/**
|
|
12
|
+
* State host that is immutable by default with explicit mutate.
|
|
13
|
+
*/
|
|
14
|
+
interface SharedState<T> {
|
|
15
|
+
/**
|
|
16
|
+
* Get the current state. Immutable.
|
|
17
|
+
*/
|
|
18
|
+
value: () => Immutable<T>;
|
|
19
|
+
/**
|
|
20
|
+
* Subscribe to state changes.
|
|
21
|
+
*/
|
|
22
|
+
on: EventEmitter<SharedStateEvents<T>>['on'];
|
|
23
|
+
/**
|
|
24
|
+
* Mutate the state.
|
|
25
|
+
*/
|
|
26
|
+
mutate: (fn: (state: T) => void, syncId?: string) => void;
|
|
27
|
+
/**
|
|
28
|
+
* Apply patches to the state.
|
|
29
|
+
*/
|
|
30
|
+
patch: (patches: Patch[], syncId?: string) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Sync IDs that have been applied to the state.
|
|
33
|
+
*/
|
|
34
|
+
syncIds: Set<string>;
|
|
35
|
+
}
|
|
36
|
+
interface SharedStateEvents<T> {
|
|
37
|
+
updated: (fullState: T, patches: Patch[] | undefined, syncId: string) => void;
|
|
38
|
+
}
|
|
39
|
+
interface SharedStateOptions<T> {
|
|
40
|
+
/**
|
|
41
|
+
* Initial state.
|
|
42
|
+
*/
|
|
43
|
+
initialValue: T;
|
|
44
|
+
/**
|
|
45
|
+
* Enable patches.
|
|
46
|
+
*
|
|
47
|
+
* @default false
|
|
48
|
+
*/
|
|
49
|
+
enablePatches?: boolean;
|
|
50
|
+
}
|
|
51
|
+
declare function createSharedState<T extends Objectish>(options: SharedStateOptions<T>): SharedState<T>;
|
|
52
|
+
//#endregion
|
|
53
|
+
export { Immutable, ImmutableArray, ImmutableMap, ImmutableObject, ImmutableSet, SharedState, SharedStateEvents, SharedStateOptions, type SharedStatePatch, createSharedState };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createEventEmitter } from "./events.mjs";
|
|
2
|
+
import { nanoid } from "./nanoid.mjs";
|
|
3
|
+
import { applyPatches, enablePatches, produce, produceWithPatches } from "immer";
|
|
4
|
+
|
|
5
|
+
//#region src/utils/shared-state.ts
|
|
6
|
+
function createSharedState(options) {
|
|
7
|
+
const { enablePatches: enablePatches$1 = false } = options;
|
|
8
|
+
const events = createEventEmitter();
|
|
9
|
+
let state = options.initialValue;
|
|
10
|
+
const syncIds = /* @__PURE__ */ new Set();
|
|
11
|
+
return {
|
|
12
|
+
on: events.on,
|
|
13
|
+
value: () => state,
|
|
14
|
+
patch: (patches, syncId = nanoid()) => {
|
|
15
|
+
if (syncIds.has(syncId)) return;
|
|
16
|
+
enablePatches();
|
|
17
|
+
state = applyPatches(state, patches);
|
|
18
|
+
syncIds.add(syncId);
|
|
19
|
+
events.emit("updated", state, void 0, syncId);
|
|
20
|
+
},
|
|
21
|
+
mutate: (fn, syncId = nanoid()) => {
|
|
22
|
+
if (syncIds.has(syncId)) return;
|
|
23
|
+
syncIds.add(syncId);
|
|
24
|
+
if (enablePatches$1) {
|
|
25
|
+
const [newState, patches] = produceWithPatches(state, fn);
|
|
26
|
+
state = newState;
|
|
27
|
+
events.emit("updated", state, patches, syncId);
|
|
28
|
+
} else {
|
|
29
|
+
state = produce(state, fn);
|
|
30
|
+
events.emit("updated", state, void 0, syncId);
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
syncIds
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { createSharedState };
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitejs/devtools-kit",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.0-alpha.
|
|
4
|
+
"version": "0.0.0-alpha.31",
|
|
5
5
|
"description": "Vite DevTools Kit",
|
|
6
6
|
"author": "VoidZero Inc.",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"homepage": "https://github.com/vitejs/devtools#readme",
|
|
9
9
|
"repository": {
|
|
10
|
-
"directory": "packages/
|
|
10
|
+
"directory": "packages/kit",
|
|
11
11
|
"type": "git",
|
|
12
12
|
"url": "git+https://github.com/vitejs/devtools.git"
|
|
13
13
|
},
|
|
@@ -19,26 +19,31 @@
|
|
|
19
19
|
],
|
|
20
20
|
"sideEffects": false,
|
|
21
21
|
"exports": {
|
|
22
|
-
".": "./dist/index.
|
|
23
|
-
"./client": "./dist/client.
|
|
22
|
+
".": "./dist/index.mjs",
|
|
23
|
+
"./client": "./dist/client.mjs",
|
|
24
|
+
"./constants": "./dist/constants.mjs",
|
|
25
|
+
"./utils/events": "./dist/utils/events.mjs",
|
|
26
|
+
"./utils/nanoid": "./dist/utils/nanoid.mjs",
|
|
27
|
+
"./utils/shared-state": "./dist/utils/shared-state.mjs",
|
|
24
28
|
"./package.json": "./package.json"
|
|
25
29
|
},
|
|
26
|
-
"
|
|
27
|
-
"module": "./dist/index.js",
|
|
28
|
-
"types": "./dist/index.d.ts",
|
|
30
|
+
"types": "./dist/index.d.mts",
|
|
29
31
|
"files": [
|
|
30
|
-
"dist"
|
|
32
|
+
"dist",
|
|
33
|
+
"skills"
|
|
31
34
|
],
|
|
32
35
|
"peerDependencies": {
|
|
33
|
-
"vite": "
|
|
36
|
+
"vite": "*"
|
|
34
37
|
},
|
|
35
38
|
"dependencies": {
|
|
36
|
-
"birpc": "^
|
|
37
|
-
"
|
|
39
|
+
"birpc": "^4.0.0",
|
|
40
|
+
"immer": "^11.1.3",
|
|
41
|
+
"@vitejs/devtools-rpc": "0.0.0-alpha.31"
|
|
38
42
|
},
|
|
39
43
|
"devDependencies": {
|
|
40
|
-
"
|
|
41
|
-
"
|
|
44
|
+
"my-ua-parser": "^2.0.4",
|
|
45
|
+
"tsdown": "^0.20.2",
|
|
46
|
+
"vite": "^8.0.0-beta.13"
|
|
42
47
|
},
|
|
43
48
|
"scripts": {
|
|
44
49
|
"build": "tsdown",
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: writing-vite-devtools-integrations
|
|
3
|
+
description: >
|
|
4
|
+
Creates devtools integrations for Vite using @vitejs/devtools-kit.
|
|
5
|
+
Use when building Vite plugins with devtools panels, RPC functions,
|
|
6
|
+
dock entries, shared state, or any devtools-related functionality.
|
|
7
|
+
Applies to files importing from @vitejs/devtools-kit or containing
|
|
8
|
+
devtools.setup hooks in Vite plugins.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Vite DevTools Kit
|
|
12
|
+
|
|
13
|
+
Build custom developer tools that integrate with Vite DevTools using `@vitejs/devtools-kit`.
|
|
14
|
+
|
|
15
|
+
## Core Concepts
|
|
16
|
+
|
|
17
|
+
A DevTools plugin extends a Vite plugin with a `devtools.setup(ctx)` hook. The context provides:
|
|
18
|
+
|
|
19
|
+
| Property | Purpose |
|
|
20
|
+
|----------|---------|
|
|
21
|
+
| `ctx.docks` | Register dock entries (iframe, action, custom-render) |
|
|
22
|
+
| `ctx.views` | Host static files for UI |
|
|
23
|
+
| `ctx.rpc` | Register RPC functions, broadcast to clients |
|
|
24
|
+
| `ctx.rpc.sharedState` | Synchronized server-client state |
|
|
25
|
+
| `ctx.viteConfig` | Resolved Vite configuration |
|
|
26
|
+
| `ctx.viteServer` | Dev server instance (dev mode only) |
|
|
27
|
+
| `ctx.mode` | `'dev'` or `'build'` |
|
|
28
|
+
|
|
29
|
+
## Quick Start: Minimal Plugin
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
/// <reference types="@vitejs/devtools-kit" />
|
|
33
|
+
import type { Plugin } from 'vite'
|
|
34
|
+
|
|
35
|
+
export default function myPlugin(): Plugin {
|
|
36
|
+
return {
|
|
37
|
+
name: 'my-plugin',
|
|
38
|
+
devtools: {
|
|
39
|
+
setup(ctx) {
|
|
40
|
+
ctx.docks.register({
|
|
41
|
+
id: 'my-plugin',
|
|
42
|
+
title: 'My Plugin',
|
|
43
|
+
icon: 'ph:puzzle-piece-duotone',
|
|
44
|
+
type: 'iframe',
|
|
45
|
+
url: 'https://example.com/devtools',
|
|
46
|
+
})
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Quick Start: Full Integration
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
/// <reference types="@vitejs/devtools-kit" />
|
|
57
|
+
import type { Plugin } from 'vite'
|
|
58
|
+
import { fileURLToPath } from 'node:url'
|
|
59
|
+
import { defineRpcFunction } from '@vitejs/devtools-kit'
|
|
60
|
+
|
|
61
|
+
export default function myAnalyzer(): Plugin {
|
|
62
|
+
const data = new Map<string, { size: number }>()
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
name: 'my-analyzer',
|
|
66
|
+
|
|
67
|
+
// Collect data in Vite hooks
|
|
68
|
+
transform(code, id) {
|
|
69
|
+
data.set(id, { size: code.length })
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
devtools: {
|
|
73
|
+
setup(ctx) {
|
|
74
|
+
// 1. Host static UI
|
|
75
|
+
const clientPath = fileURLToPath(
|
|
76
|
+
new URL('../dist/client', import.meta.url)
|
|
77
|
+
)
|
|
78
|
+
ctx.views.hostStatic('/.my-analyzer/', clientPath)
|
|
79
|
+
|
|
80
|
+
// 2. Register dock entry
|
|
81
|
+
ctx.docks.register({
|
|
82
|
+
id: 'my-analyzer',
|
|
83
|
+
title: 'Analyzer',
|
|
84
|
+
icon: 'ph:chart-bar-duotone',
|
|
85
|
+
type: 'iframe',
|
|
86
|
+
url: '/.my-analyzer/',
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
// 3. Register RPC function
|
|
90
|
+
ctx.rpc.register(
|
|
91
|
+
defineRpcFunction({
|
|
92
|
+
name: 'my-analyzer:get-data',
|
|
93
|
+
type: 'query',
|
|
94
|
+
setup: () => ({
|
|
95
|
+
handler: async () => Array.from(data.entries()),
|
|
96
|
+
}),
|
|
97
|
+
})
|
|
98
|
+
)
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Namespacing Convention
|
|
106
|
+
|
|
107
|
+
**CRITICAL**: Always prefix RPC functions, shared state keys, and dock IDs with your plugin name:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
// Good - namespaced
|
|
111
|
+
'my-plugin:get-modules'
|
|
112
|
+
'my-plugin:state'
|
|
113
|
+
|
|
114
|
+
// Bad - may conflict
|
|
115
|
+
'get-modules'
|
|
116
|
+
'state'
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Dock Entry Types
|
|
120
|
+
|
|
121
|
+
| Type | Use Case |
|
|
122
|
+
|------|----------|
|
|
123
|
+
| `iframe` | Full UI panels, dashboards (most common) |
|
|
124
|
+
| `action` | Buttons that trigger client-side scripts (inspectors, toggles) |
|
|
125
|
+
| `custom-render` | Direct DOM access in panel (framework mounting) |
|
|
126
|
+
|
|
127
|
+
### Iframe Entry
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
ctx.docks.register({
|
|
131
|
+
id: 'my-plugin',
|
|
132
|
+
title: 'My Plugin',
|
|
133
|
+
icon: 'ph:house-duotone',
|
|
134
|
+
type: 'iframe',
|
|
135
|
+
url: '/.my-plugin/',
|
|
136
|
+
})
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Action Entry
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
ctx.docks.register({
|
|
143
|
+
id: 'my-inspector',
|
|
144
|
+
title: 'Inspector',
|
|
145
|
+
icon: 'ph:cursor-duotone',
|
|
146
|
+
type: 'action',
|
|
147
|
+
action: {
|
|
148
|
+
importFrom: 'my-plugin/devtools-action',
|
|
149
|
+
importName: 'default',
|
|
150
|
+
},
|
|
151
|
+
})
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Custom Render Entry
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
ctx.docks.register({
|
|
158
|
+
id: 'my-custom',
|
|
159
|
+
title: 'Custom View',
|
|
160
|
+
icon: 'ph:code-duotone',
|
|
161
|
+
type: 'custom-render',
|
|
162
|
+
renderer: {
|
|
163
|
+
importFrom: 'my-plugin/devtools-renderer',
|
|
164
|
+
importName: 'default',
|
|
165
|
+
},
|
|
166
|
+
})
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## RPC Functions
|
|
170
|
+
|
|
171
|
+
### Server-Side Definition
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
import { defineRpcFunction } from '@vitejs/devtools-kit'
|
|
175
|
+
|
|
176
|
+
const getModules = defineRpcFunction({
|
|
177
|
+
name: 'my-plugin:get-modules',
|
|
178
|
+
type: 'query', // 'query' | 'action' | 'static'
|
|
179
|
+
setup: ctx => ({
|
|
180
|
+
handler: async (filter?: string) => {
|
|
181
|
+
// ctx has full DevToolsNodeContext
|
|
182
|
+
return modules.filter(m => !filter || m.includes(filter))
|
|
183
|
+
},
|
|
184
|
+
}),
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
// Register in setup
|
|
188
|
+
ctx.rpc.register(getModules)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Client-Side Call (iframe)
|
|
192
|
+
|
|
193
|
+
```ts
|
|
194
|
+
import { getDevToolsRpcClient } from '@vitejs/devtools-kit/client'
|
|
195
|
+
|
|
196
|
+
const rpc = await getDevToolsRpcClient()
|
|
197
|
+
const modules = await rpc.call('my-plugin:get-modules', 'src/')
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Client-Side Call (action/renderer script)
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
import type { DevToolsClientScriptContext } from '@vitejs/devtools-kit/client'
|
|
204
|
+
|
|
205
|
+
export default function setup(ctx: DevToolsClientScriptContext) {
|
|
206
|
+
ctx.current.events.on('entry:activated', async () => {
|
|
207
|
+
const data = await ctx.current.rpc.call('my-plugin:get-data')
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Broadcasting to Clients
|
|
213
|
+
|
|
214
|
+
```ts
|
|
215
|
+
// Server broadcasts to all clients
|
|
216
|
+
ctx.rpc.broadcast({
|
|
217
|
+
method: 'my-plugin:on-update',
|
|
218
|
+
args: [{ changedFile: '/src/main.ts' }],
|
|
219
|
+
})
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Type Safety
|
|
223
|
+
|
|
224
|
+
Extend the DevTools Kit interfaces for full type checking:
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
// src/types.ts
|
|
228
|
+
import '@vitejs/devtools-kit'
|
|
229
|
+
|
|
230
|
+
declare module '@vitejs/devtools-kit' {
|
|
231
|
+
interface DevToolsRpcServerFunctions {
|
|
232
|
+
'my-plugin:get-modules': (filter?: string) => Promise<Module[]>
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
interface DevToolsRpcClientFunctions {
|
|
236
|
+
'my-plugin:on-update': (data: { changedFile: string }) => void
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
interface DevToolsRpcSharedStates {
|
|
240
|
+
'my-plugin:state': MyPluginState
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Shared State
|
|
246
|
+
|
|
247
|
+
### Server-Side
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
const state = await ctx.rpc.sharedState.get('my-plugin:state', {
|
|
251
|
+
initialValue: { count: 0, items: [] },
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
// Read
|
|
255
|
+
console.log(state.value())
|
|
256
|
+
|
|
257
|
+
// Mutate (auto-syncs to clients)
|
|
258
|
+
state.mutate((draft) => {
|
|
259
|
+
draft.count += 1
|
|
260
|
+
draft.items.push('new item')
|
|
261
|
+
})
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Client-Side
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
const client = await getDevToolsRpcClient()
|
|
268
|
+
const state = await client.rpc.sharedState.get('my-plugin:state')
|
|
269
|
+
|
|
270
|
+
// Read
|
|
271
|
+
console.log(state.value())
|
|
272
|
+
|
|
273
|
+
// Subscribe to changes
|
|
274
|
+
state.on('updated', (newState) => {
|
|
275
|
+
console.log('State updated:', newState)
|
|
276
|
+
})
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Client Scripts
|
|
280
|
+
|
|
281
|
+
For action buttons and custom renderers:
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
// src/devtools-action.ts
|
|
285
|
+
import type { DevToolsClientScriptContext } from '@vitejs/devtools-kit/client'
|
|
286
|
+
|
|
287
|
+
export default function setup(ctx: DevToolsClientScriptContext) {
|
|
288
|
+
ctx.current.events.on('entry:activated', () => {
|
|
289
|
+
console.log('Action activated')
|
|
290
|
+
// Your inspector/tool logic here
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
ctx.current.events.on('entry:deactivated', () => {
|
|
294
|
+
console.log('Action deactivated')
|
|
295
|
+
// Cleanup
|
|
296
|
+
})
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Export from package.json:
|
|
301
|
+
|
|
302
|
+
```json
|
|
303
|
+
{
|
|
304
|
+
"exports": {
|
|
305
|
+
".": "./dist/index.mjs",
|
|
306
|
+
"./devtools-action": "./dist/devtools-action.mjs"
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Best Practices
|
|
312
|
+
|
|
313
|
+
1. **Always namespace** - Prefix all identifiers with your plugin name
|
|
314
|
+
2. **Use type augmentation** - Extend `DevToolsRpcServerFunctions` for type-safe RPC
|
|
315
|
+
3. **Keep state serializable** - No functions or circular references in shared state
|
|
316
|
+
4. **Batch mutations** - Use single `mutate()` call for multiple changes
|
|
317
|
+
5. **Host static files** - Use `ctx.views.hostStatic()` for your UI assets
|
|
318
|
+
6. **Use Iconify icons** - Prefer `ph:*` (Phosphor) icons: `icon: 'ph:chart-bar-duotone'`
|
|
319
|
+
|
|
320
|
+
## Further Reading
|
|
321
|
+
|
|
322
|
+
- [RPC Patterns](./references/rpc-patterns.md) - Advanced RPC patterns and type utilities
|
|
323
|
+
- [Dock Entry Types](./references/dock-entry-types.md) - Detailed dock configuration options
|
|
324
|
+
- [Shared State Patterns](./references/shared-state-patterns.md) - Framework integration examples
|
|
325
|
+
- [Project Structure](./references/project-structure.md) - Recommended file organization
|