Skip to content

Commit 4e88d9a

Browse files
committed
Component tracking start
1 parent 0de9cfa commit 4e88d9a

7 files changed

Lines changed: 109 additions & 36 deletions

File tree

extension/src/components/Graph.tsx

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,7 @@ export function GraphVisualization({
3333
if (!update.signalId) return;
3434

3535
// Determine signal type
36-
let type: "signal" | "computed" | "effect" = "signal";
37-
if (update.type === "effect") {
38-
type = "effect";
39-
} else if (update.subscribedTo) {
40-
type = "computed";
41-
}
42-
36+
let type: "signal" | "computed" | "effect" = update.signalType;
4337
// Track depth
4438
const currentDepth = update.depth || 0;
4539
depthMap.set(update.signalId, currentDepth);
@@ -64,18 +58,6 @@ export function GraphVisualization({
6458
source: update.subscribedTo,
6559
target: update.signalId,
6660
});
67-
68-
// Also ensure source node exists
69-
if (!nodes.has(update.subscribedTo)) {
70-
nodes.set(update.subscribedTo, {
71-
id: update.subscribedTo,
72-
name: update.signalName,
73-
type: "signal",
74-
x: 0,
75-
y: 0,
76-
depth: currentDepth - 1,
77-
});
78-
}
7961
}
8062
}
8163
});
@@ -182,7 +164,9 @@ export function GraphVisualization({
182164
className="graph-text"
183165
x={node.x}
184166
y={node.y}
185-
textLength="40"
167+
textLength={
168+
8 * (node.name.length > 8 ? 11 : node.name.length)
169+
}
186170
lengthAdjust="spacingAndGlyphs"
187171
>
188172
{node.name.length > 8

extension/src/components/Header.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ interface HeaderProps {
99

1010
export function Header({ onToggleSettings }: HeaderProps) {
1111
const onTogglePause = () => {
12-
connectionStore.isPaused = !connectionStore.isPaused;
12+
updatesStore.isPaused.value = !updatesStore.isPaused.value;
1313
};
1414

1515
const onClear = () => {
@@ -28,8 +28,8 @@ export function Header({ onToggleSettings }: HeaderProps) {
2828
<div className="header-controls">
2929
{onClear && <Button onClick={onClear}>Clear</Button>}
3030
{onTogglePause && (
31-
<Button onClick={onTogglePause} active={connectionStore.isPaused}>
32-
{connectionStore.isPaused ? "Resume" : "Pause"}
31+
<Button onClick={onTogglePause} active={updatesStore.isPaused.value}>
32+
{updatesStore.isPaused.value ? "Resume" : "Pause"}
3333
</Button>
3434
)}
3535
{onToggleSettings && (

extension/src/models/ConnectionModel.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ export const sendMessage = (message: any) => {
1010

1111
const createConnectionModel = () => {
1212
const status = signal<Status>("connecting");
13-
const isPaused = signal<boolean>(false);
1413
const isBackgroundConnected = signal(false);
1514
const isContentScriptConnected = signal(false);
1615
const isConnected = signal(false);
@@ -34,8 +33,6 @@ const createConnectionModel = () => {
3433
};
3534

3635
effect(() => {
37-
if (isPaused.value) return;
38-
3936
const handleMessage = (event: MessageEvent) => {
4037
// Only accept messages from the same origin (devtools context)
4138
if (event.origin !== window.location.origin) return;
@@ -109,9 +106,6 @@ const createConnectionModel = () => {
109106
get status() {
110107
return status.value;
111108
},
112-
get isPaused() {
113-
return isPaused.value;
114-
},
115109
get message() {
116110
return message.value;
117111
},
@@ -122,9 +116,6 @@ const createConnectionModel = () => {
122116
set status(newStatus: Status) {
123117
status.value = newStatus;
124118
},
125-
set isPaused(newPaused: boolean) {
126-
isPaused.value = newPaused;
127-
},
128119
set isBackgroundConnected(newConnected: boolean) {
129120
isBackgroundConnected.value = newConnected;
130121
},

extension/src/models/UpdatesModel.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { signal, computed } from "@preact/signals";
1+
import { signal, computed, effect } from "@preact/signals";
22
import { Divider, SignalUpdate } from "../types";
33

44
const createUpdatesModel = () => {
55
const updates = signal<(SignalUpdate | Divider)[]>([]);
66
const lastUpdateId = signal<number>(0);
7+
const isPaused = signal<boolean>(false);
78

89
const addUpdate = (
910
update: SignalUpdate | Divider | Array<SignalUpdate | Divider>
@@ -38,12 +39,44 @@ const createUpdatesModel = () => {
3839
lastUpdateId.value = 0;
3940
};
4041

42+
effect(() => {
43+
if (isPaused.value) return;
44+
45+
const handleMessage = (event: MessageEvent) => {
46+
// Only accept messages from the same origin (devtools context)
47+
if (event.origin !== window.location.origin) return;
48+
49+
const { type, payload } = event.data;
50+
51+
switch (type) {
52+
case "SIGNALS_UPDATE": {
53+
const signalUpdates = payload.updates;
54+
const updatesArray: Array<SignalUpdate | Divider> = Array.isArray(
55+
signalUpdates
56+
)
57+
? signalUpdates
58+
: [signalUpdates];
59+
60+
updatesArray.reverse();
61+
updatesArray.push({ type: "divider" });
62+
63+
updatesStore.addUpdate(updatesArray);
64+
break;
65+
}
66+
}
67+
};
68+
69+
window.addEventListener("message", handleMessage);
70+
return () => window.removeEventListener("message", handleMessage);
71+
});
72+
4173
return {
4274
updates,
4375
signalCounts,
4476
addUpdate,
4577
clearUpdates,
4678
hasUpdates,
79+
isPaused,
4780
};
4881
};
4982

packages/debug/src/devtools.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,32 @@ import { UpdateInfo } from "./internal";
22

33
// Communication layer for Chrome DevTools Extension
44
export interface DevToolsMessage {
5-
type: "SIGNALS_UPDATE" | "SIGNALS_INIT" | "SIGNALS_CONFIG";
5+
type:
6+
| "SIGNALS_UPDATE"
7+
| "SIGNALS_INIT"
8+
| "SIGNALS_CONFIG"
9+
| "ENTER_COMPONENT"
10+
| "EXIT_COMPONENT";
611
payload: any;
712
timestamp: number;
813
}
914

10-
interface SignalsDevToolsAPI {
15+
export interface SignalsDevToolsAPI {
1116
onUpdate: (callback: (updateInfo: UpdateInfo[]) => void) => () => void;
1217
onInit: (callback: () => void) => () => void;
1318
sendConfig: (config: any) => void;
1419
sendUpdate: (updateInfo: UpdateInfo[]) => void;
1520
isConnected: () => boolean;
21+
enterComponent: (name: string) => void;
22+
exitComponent: () => void;
1623
}
1724

1825
class DevToolsCommunicator {
1926
public listeners: Map<string, Set<Function>> = new Map();
2027
public isExtensionConnected = false;
2128
public messageQueue: DevToolsMessage[] = [];
2229
public readonly maxQueueSize = 100;
30+
public componentName: string | null = null;
2331

2432
constructor() {
2533
this.setupCommunication();
@@ -139,6 +147,14 @@ class DevToolsCommunicator {
139147
};
140148
}
141149

150+
public enterComponent(name: string) {
151+
this.componentName = name;
152+
}
153+
154+
public exitComponent() {
155+
this.componentName = null;
156+
}
157+
142158
public getSignalName(signal: any): string {
143159
// Try to get a meaningful name for the signal
144160
if (signal.displayName) return signal.displayName;
@@ -182,10 +198,16 @@ if (typeof window !== "undefined") {
182198
sendConfig: config => getDevToolsCommunicator().sendConfig(config),
183199
sendUpdate: updateInfo => getDevToolsCommunicator().sendUpdate(updateInfo),
184200
isConnected: () => getDevToolsCommunicator().isConnected(),
201+
enterComponent: name => {
202+
getDevToolsCommunicator().enterComponent(name);
203+
},
204+
exitComponent: () => {
205+
getDevToolsCommunicator().exitComponent();
206+
},
185207
};
186208

187209
// Expose API globally for the Chrome extension to use
188-
(window as any).__PREACT_SIGNALS_DEVTOOLS__ = api;
210+
window.__PREACT_SIGNALS_DEVTOOLS__ = api;
189211

190212
// Announce availability to Chrome extension
191213
if (window.postMessage) {
@@ -210,3 +232,9 @@ if (typeof window !== "undefined") {
210232
}, 100);
211233
}
212234
}
235+
236+
declare global {
237+
interface Window {
238+
__PREACT_SIGNALS_DEVTOOLS__: SignalsDevToolsAPI;
239+
}
240+
}

packages/preact/src/index.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,14 @@ Object.defineProperties(Signal.prototype, {
171171

172172
/** Inject low-level property/attribute bindings for Signals into Preact's diff */
173173
hook(OptionsTypes.DIFF, (old, vnode) => {
174+
if (
175+
typeof vnode.type === "function" &&
176+
typeof window !== "undefined" &&
177+
window.__PREACT_SIGNALS_DEVTOOLS__
178+
) {
179+
window.__PREACT_SIGNALS_DEVTOOLS__.exitComponent();
180+
}
181+
174182
if (typeof vnode.type === "string") {
175183
let signalProps: Record<string, any> | undefined;
176184

@@ -192,6 +200,16 @@ hook(OptionsTypes.DIFF, (old, vnode) => {
192200

193201
/** Set up Updater before rendering a component */
194202
hook(OptionsTypes.RENDER, (old, vnode) => {
203+
if (
204+
typeof vnode.type === "function" &&
205+
typeof window !== "undefined" &&
206+
window.__PREACT_SIGNALS_DEVTOOLS__
207+
) {
208+
window.__PREACT_SIGNALS_DEVTOOLS__.enterComponent(
209+
vnode.type.displayName || vnode.type.name || "Unknown"
210+
);
211+
}
212+
195213
// Ignore the Fragment inserted by preact.createElement().
196214
if (vnode.type !== Fragment) {
197215
setCurrentUpdater();
@@ -220,13 +238,25 @@ hook(OptionsTypes.RENDER, (old, vnode) => {
220238

221239
/** Finish current updater if a component errors */
222240
hook(OptionsTypes.CATCH_ERROR, (old, error, vnode, oldVNode) => {
241+
if (typeof window !== "undefined" && window.__PREACT_SIGNALS_DEVTOOLS__) {
242+
window.__PREACT_SIGNALS_DEVTOOLS__.exitComponent();
243+
}
244+
223245
setCurrentUpdater();
224246
currentComponent = undefined;
225247
old(error, vnode, oldVNode);
226248
});
227249

228250
/** Finish current updater after rendering any VNode */
229251
hook(OptionsTypes.DIFFED, (old, vnode) => {
252+
if (
253+
typeof vnode.type === "function" &&
254+
typeof window !== "undefined" &&
255+
window.__PREACT_SIGNALS_DEVTOOLS__
256+
) {
257+
window.__PREACT_SIGNALS_DEVTOOLS__.exitComponent();
258+
}
259+
230260
setCurrentUpdater();
231261
currentComponent = undefined;
232262

packages/preact/src/internal.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Component } from "preact";
22
import { Signal } from "@preact/signals-core";
3+
import type { SignalsDevToolsAPI } from "../../debug/src/devtools";
34

45
export interface Effect {
56
_sources: object | undefined;
@@ -62,3 +63,9 @@ export type HookFn<T extends keyof OptionsType> = (
6263
old: OptionsType[T],
6364
...a: Parameters<OptionsType[T]>
6465
) => ReturnType<OptionsType[T]>;
66+
67+
declare global {
68+
interface Window {
69+
__PREACT_SIGNALS_DEVTOOLS__: SignalsDevToolsAPI;
70+
}
71+
}

0 commit comments

Comments
 (0)