Skip to content

Commit ba34e6f

Browse files
authored
fix: sync SWRDevTools and a devtool panel (#27)
* fix: sync SWRDevTools and a devtool panel * fix: type errors
1 parent 9d4c46b commit ba34e6f

File tree

5 files changed

+127
-52
lines changed

5 files changed

+127
-52
lines changed

packages/swr-devtools-extensions/src/app.tsx

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,45 @@ const rootEl = document.getElementById("app");
1010
const port = chrome.runtime.connect({
1111
name: "panel",
1212
});
13-
// @ts-ignore
14-
port.onMessage.addListener((message: ContentMessage) => {
15-
if (message.type === "initialized") {
16-
cache.clear();
17-
ReactDOM.render(<SWRDevToolPanel cache={cache} isReady={false} />, rootEl);
18-
} else if (message.type === "updated_cache") {
19-
const { key, value } = message.payload;
20-
cache.set(key, value);
21-
ReactDOM.render(<SWRDevToolPanel cache={cache} />, rootEl);
22-
}
23-
});
2413
port.onDisconnect.addListener(() => {
2514
cache.clear();
26-
ReactDOM.render(<SWRDevToolPanel cache={cache} isReady={false} />, rootEl);
15+
mounted = false;
16+
ReactDOM.render(<SWRDevToolPanel cache={null} />, rootEl);
2717
});
2818

29-
ReactDOM.render(<SWRDevToolPanel cache={cache} isReady={false} />, rootEl);
19+
let mounted = false;
20+
// @ts-ignore
21+
port.onMessage.addListener((message: ContentMessage) => {
22+
switch (message.type) {
23+
// loaded a new page
24+
case "load": {
25+
ReactDOM.render(<SWRDevToolPanel cache={null} />, rootEl);
26+
break;
27+
}
28+
29+
// initialized SWRDevTools, start rendering a devtool panel
30+
case "initialized": {
31+
cache.clear();
32+
mounted = true;
33+
ReactDOM.render(<SWRDevToolPanel cache={cache} />, rootEl);
34+
break;
35+
}
36+
37+
case "updated_swr_cache": {
38+
const { key, value } = message.payload;
39+
// trigger re-rendering
40+
cache.set(key, value);
41+
42+
// mount a devtool panel if it hasn't been mounted yet.
43+
if (mounted === false) {
44+
ReactDOM.render(<SWRDevToolPanel cache={cache} />, rootEl);
45+
mounted = true;
46+
}
47+
break;
48+
}
49+
50+
default: {
51+
// noop
52+
}
53+
}
54+
});

packages/swr-devtools-extensions/src/background.ts

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,46 @@ import type { ContentMessage } from "./content";
33
let panelPort: chrome.runtime.Port | null = null;
44
let contentPort: chrome.runtime.Port | null = null;
55

6-
const queuedMessages: any[] = [];
7-
const flushQueuedMessages = () => {
8-
if (panelPort === null) {
9-
return;
10-
}
11-
for (const queuedMessage of queuedMessages) {
12-
panelPort.postMessage(queuedMessage);
13-
}
14-
queuedMessages.length = 0;
15-
};
16-
const enqueueMessage = (message: any) => {
17-
queuedMessages.push(message);
18-
};
6+
// queued messages until a panel is connected
7+
const queuedContentMessages: any[] = [];
198

209
chrome.runtime.onConnect.addListener((port) => {
10+
console.log("on connect", port.name);
2111
// A port between a content page
2212
if (port.name === "content") {
2313
contentPort = port;
14+
if (panelPort !== null) {
15+
// notify that a panel is connected
16+
contentPort.postMessage({
17+
type: "displayed_panel",
18+
});
19+
}
2420
contentPort.onDisconnect.addListener(() => {
2521
contentPort = null;
2622
});
2723
contentPort.onMessage.addListener((message: ContentMessage) => {
2824
console.log("sent message from content to panel", message);
29-
if (panelPort === null) {
30-
enqueueMessage(message);
31-
} else {
32-
flushQueuedMessages();
25+
if (panelPort !== null) {
3326
panelPort.postMessage(message);
27+
} else {
28+
// not ready for sending messages
29+
queuedContentMessages.push(message);
3430
}
3531
});
3632
// A port between the SWR panel in devtools
3733
} else if (port.name === "panel") {
3834
panelPort = port;
39-
flushQueuedMessages();
35+
if (contentPort !== null) {
36+
// notify that a panel is connected
37+
contentPort.postMessage({
38+
type: "displayed_panel",
39+
});
40+
}
41+
// flush queued messages
42+
if (queuedContentMessages.length > 0) {
43+
queuedContentMessages.forEach((m) => panelPort?.postMessage(m));
44+
queuedContentMessages.length = 0;
45+
}
4046
panelPort.onDisconnect.addListener(() => {
4147
panelPort = null;
4248
});
Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,64 @@
11
import { DevToolsMessage } from "swr-devtools";
22

33
export type ContentMessage =
4+
| {
5+
type: "load";
6+
}
47
| {
58
type: "initialized";
69
}
710
| {
8-
type: "updated_cache";
9-
payload: DevToolsMessage["payload"];
11+
type: "updated_swr_cache";
12+
payload: any;
13+
}
14+
| {
15+
type: "load";
1016
};
1117

18+
// queued messages until a panel is displayed
19+
const queuedMessages: any[] = [];
20+
const enqueueMessage = (message: any) => {
21+
queuedMessages.push(message);
22+
};
23+
24+
let isDisplayedPanel = false;
25+
1226
// proxy messages from applications to a background script
1327
const port = chrome.runtime.connect({ name: "content" });
28+
port.onMessage.addListener((message: any) => {
29+
console.log("received from background -> content", message);
30+
// a panel has been displayed, so we sent queued messages
31+
if (message.type === "displayed_panel") {
32+
queuedMessages.forEach((m) => {
33+
port.postMessage(m);
34+
});
35+
isDisplayedPanel = true;
36+
}
37+
});
38+
39+
// A new page has been loaded.
40+
// this event is sent with any pages that don't have SWRDevTools
1441
port.postMessage({
15-
type: "initialized",
42+
type: "load",
1643
});
1744

1845
window.addEventListener("message", (e: MessageEvent<DevToolsMessage>) => {
19-
if (e.data?.type === "updated_swr_cache") {
20-
// console.log("received", e.data.cacheData);
21-
port.postMessage({
22-
type: "updated_cache",
23-
payload: e.data.payload,
24-
});
46+
switch (e.data?.type) {
47+
case "initialized": {
48+
port.postMessage(e.data);
49+
break;
50+
}
51+
case "updated_swr_cache": {
52+
if (isDisplayedPanel) {
53+
port.postMessage(e.data);
54+
} else {
55+
// enqueue a message if a panel hasn't been displayed
56+
enqueueMessage(e.data);
57+
}
58+
break;
59+
}
60+
default: {
61+
// noop
62+
}
2563
}
2664
});

packages/swr-devtools-panel/src/components/SWRDevToolPanel.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ const panels: Panel[] = [
2020
];
2121

2222
type Props = {
23-
cache: Cache;
24-
isReady?: boolean;
23+
cache: Cache | null;
2524
isFixedPosition?: boolean;
2625
};
2726

@@ -56,7 +55,7 @@ const GlobalStyle = createGlobalStyle`
5655
}
5756
`;
5857

59-
export const SWRDevToolPanel = ({ cache, isReady = true }: Props) => {
58+
export const SWRDevToolPanel = ({ cache }: Props) => {
6059
const [activePanel, setActivePanel] = useState<Panel["key"]>("current");
6160
const [selectedItemKey, setSelectedItemKey] = useState<ItemKey | null>(null);
6261
return (
@@ -74,7 +73,7 @@ export const SWRDevToolPanel = ({ cache, isReady = true }: Props) => {
7473
/>
7574
</Header>
7675
<PanelWrapper>
77-
{isReady ? (
76+
{cache !== null ? (
7877
<Panel
7978
cache={cache}
8079
type={activePanel}

packages/swr-devtools/src/SWRDevTools.tsx

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
1-
import React from "react";
1+
import React, { useLayoutEffect } from "react";
22
import { useSWRConfig, SWRConfig, Middleware, Cache } from "swr";
33

44
import { injectSWRCache, isMetaCache } from "./swr-cache";
55

66
const injected = new WeakSet();
77

8-
export type DevToolsMessage = {
9-
type: "updated_swr_cache";
10-
payload: {
11-
key: string;
12-
value: any;
13-
};
14-
};
8+
export type DevToolsMessage =
9+
| {
10+
type: "updated_swr_cache";
11+
payload: {
12+
key: string;
13+
value: any;
14+
};
15+
}
16+
| {
17+
type: "initialized";
18+
};
1519

1620
const inject = (cache: Cache) =>
1721
injectSWRCache(cache, (key: string, value: any) => {
@@ -31,6 +35,9 @@ const inject = (cache: Cache) =>
3135
});
3236

3337
const swrdevtools: Middleware = (useSWRNext) => (key, fn, config) => {
38+
useLayoutEffect(() => {
39+
window.postMessage({ type: "initialized" }, "*");
40+
}, []);
3441
// FIXME: I'll use mutate to support mutating from a devtool panel.
3542
const { cache /* , mutate */ } = useSWRConfig();
3643

0 commit comments

Comments
 (0)