Skip to content

Commit 55934bd

Browse files
Prevent duplicate dev tools
1 parent 9791c0b commit 55934bd

1 file changed

Lines changed: 52 additions & 7 deletions

File tree

packages/template/src/dev-tool/dev-tool-core.ts

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ type DevToolState = {
5555

5656
const STORAGE_KEY = '__stack-dev-tool-state';
5757
const TRIGGER_POS_KEY = 'stack-devtool-trigger-position';
58+
const ROOT_ID = '__stack-dev-tool-root';
59+
const GLOBAL_INSTANCE_KEY = '__stack-dev-tool-instance';
5860
const MAX_LOG_ENTRIES = 500;
5961
const DRAG_THRESHOLD = 5;
6062

@@ -136,6 +138,29 @@ type LogStore = {
136138
subscribe(fn: () => void): () => void;
137139
};
138140

141+
type DevToolGlobalInstance = {
142+
cleanup: () => void;
143+
};
144+
145+
function isDevToolGlobalInstance(value: unknown): value is DevToolGlobalInstance {
146+
return typeof value === 'object' && value !== null && typeof Reflect.get(value, 'cleanup') === 'function';
147+
}
148+
149+
function getGlobalDevToolInstance(): DevToolGlobalInstance | null {
150+
if (typeof window === 'undefined') return null;
151+
const value: unknown = Reflect.get(window, GLOBAL_INSTANCE_KEY);
152+
return isDevToolGlobalInstance(value) ? value : null;
153+
}
154+
155+
function setGlobalDevToolInstance(instance: DevToolGlobalInstance | null) {
156+
if (typeof window === 'undefined') return;
157+
if (instance === null) {
158+
Reflect.deleteProperty(window, GLOBAL_INSTANCE_KEY);
159+
} else {
160+
Reflect.set(window, GLOBAL_INSTANCE_KEY, instance);
161+
}
162+
}
163+
139164
function getGlobalLogStore(): LogStore {
140165
const g = globalThis as any;
141166
if (!g.__STACK_DEV_TOOL_LOG_STORE__) {
@@ -2287,8 +2312,15 @@ export function createDevTool(app: StackClientApp<true>): () => void {
22872312
const body = Reflect.get(document, 'body');
22882313
if (!hasAppendChild(body)) return () => {};
22892314

2315+
getGlobalDevToolInstance()?.cleanup();
2316+
let existingRoot = document.getElementById(ROOT_ID);
2317+
while (existingRoot !== null) {
2318+
existingRoot.remove();
2319+
existingRoot = document.getElementById(ROOT_ID);
2320+
}
2321+
22902322
const root = document.createElement('div');
2291-
root.id = '__stack-dev-tool-root';
2323+
root.id = ROOT_ID;
22922324
body.appendChild(root);
22932325

22942326
const wrapper = h('div', { className: 'stack-devtool' });
@@ -2363,13 +2395,26 @@ export function createDevTool(app: StackClientApp<true>): () => void {
23632395
}
23642396
});
23652397

2398+
let didCleanup = false;
2399+
const instance: DevToolGlobalInstance = {
2400+
cleanup: () => {
2401+
if (didCleanup) return;
2402+
didCleanup = true;
2403+
if (getGlobalDevToolInstance() === instance) {
2404+
setGlobalDevToolInstance(null);
2405+
}
2406+
trigger.cleanup();
2407+
removeRequestListener();
2408+
panel?.cleanup();
2409+
if (root.parentNode) {
2410+
root.parentNode.removeChild(root);
2411+
}
2412+
},
2413+
};
2414+
setGlobalDevToolInstance(instance);
2415+
23662416
return () => {
2367-
trigger.cleanup();
2368-
removeRequestListener();
2369-
panel?.cleanup();
2370-
if (root.parentNode) {
2371-
root.parentNode.removeChild(root);
2372-
}
2417+
instance.cleanup();
23732418
};
23742419
}
23752420

0 commit comments

Comments
 (0)