Skip to content

Commit

Permalink
fix: sync SWRDevTools and a devtool panel (#27)
Browse files Browse the repository at this point in the history
* fix: sync SWRDevTools and a devtool panel

* fix: type errors
  • Loading branch information
koba04 committed Sep 16, 2021
1 parent 9d4c46b commit ba34e6f
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 52 deletions.
51 changes: 38 additions & 13 deletions packages/swr-devtools-extensions/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,45 @@ const rootEl = document.getElementById("app");
const port = chrome.runtime.connect({
name: "panel",
});
// @ts-ignore
port.onMessage.addListener((message: ContentMessage) => {
if (message.type === "initialized") {
cache.clear();
ReactDOM.render(<SWRDevToolPanel cache={cache} isReady={false} />, rootEl);
} else if (message.type === "updated_cache") {
const { key, value } = message.payload;
cache.set(key, value);
ReactDOM.render(<SWRDevToolPanel cache={cache} />, rootEl);
}
});
port.onDisconnect.addListener(() => {
cache.clear();
ReactDOM.render(<SWRDevToolPanel cache={cache} isReady={false} />, rootEl);
mounted = false;
ReactDOM.render(<SWRDevToolPanel cache={null} />, rootEl);
});

ReactDOM.render(<SWRDevToolPanel cache={cache} isReady={false} />, rootEl);
let mounted = false;
// @ts-ignore
port.onMessage.addListener((message: ContentMessage) => {
switch (message.type) {
// loaded a new page
case "load": {
ReactDOM.render(<SWRDevToolPanel cache={null} />, rootEl);
break;
}

// initialized SWRDevTools, start rendering a devtool panel
case "initialized": {
cache.clear();
mounted = true;
ReactDOM.render(<SWRDevToolPanel cache={cache} />, rootEl);
break;
}

case "updated_swr_cache": {
const { key, value } = message.payload;
// trigger re-rendering
cache.set(key, value);

// mount a devtool panel if it hasn't been mounted yet.
if (mounted === false) {
ReactDOM.render(<SWRDevToolPanel cache={cache} />, rootEl);
mounted = true;
}
break;
}

default: {
// noop
}
}
});
42 changes: 24 additions & 18 deletions packages/swr-devtools-extensions/src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,46 @@ import type { ContentMessage } from "./content";
let panelPort: chrome.runtime.Port | null = null;
let contentPort: chrome.runtime.Port | null = null;

const queuedMessages: any[] = [];
const flushQueuedMessages = () => {
if (panelPort === null) {
return;
}
for (const queuedMessage of queuedMessages) {
panelPort.postMessage(queuedMessage);
}
queuedMessages.length = 0;
};
const enqueueMessage = (message: any) => {
queuedMessages.push(message);
};
// queued messages until a panel is connected
const queuedContentMessages: any[] = [];

chrome.runtime.onConnect.addListener((port) => {
console.log("on connect", port.name);
// A port between a content page
if (port.name === "content") {
contentPort = port;
if (panelPort !== null) {
// notify that a panel is connected
contentPort.postMessage({
type: "displayed_panel",
});
}
contentPort.onDisconnect.addListener(() => {
contentPort = null;
});
contentPort.onMessage.addListener((message: ContentMessage) => {
console.log("sent message from content to panel", message);
if (panelPort === null) {
enqueueMessage(message);
} else {
flushQueuedMessages();
if (panelPort !== null) {
panelPort.postMessage(message);
} else {
// not ready for sending messages
queuedContentMessages.push(message);
}
});
// A port between the SWR panel in devtools
} else if (port.name === "panel") {
panelPort = port;
flushQueuedMessages();
if (contentPort !== null) {
// notify that a panel is connected
contentPort.postMessage({
type: "displayed_panel",
});
}
// flush queued messages
if (queuedContentMessages.length > 0) {
queuedContentMessages.forEach((m) => panelPort?.postMessage(m));
queuedContentMessages.length = 0;
}
panelPort.onDisconnect.addListener(() => {
panelPort = null;
});
Expand Down
56 changes: 47 additions & 9 deletions packages/swr-devtools-extensions/src/content.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,64 @@
import { DevToolsMessage } from "swr-devtools";

export type ContentMessage =
| {
type: "load";
}
| {
type: "initialized";
}
| {
type: "updated_cache";
payload: DevToolsMessage["payload"];
type: "updated_swr_cache";
payload: any;
}
| {
type: "load";
};

// queued messages until a panel is displayed
const queuedMessages: any[] = [];
const enqueueMessage = (message: any) => {
queuedMessages.push(message);
};

let isDisplayedPanel = false;

// proxy messages from applications to a background script
const port = chrome.runtime.connect({ name: "content" });
port.onMessage.addListener((message: any) => {
console.log("received from background -> content", message);
// a panel has been displayed, so we sent queued messages
if (message.type === "displayed_panel") {
queuedMessages.forEach((m) => {
port.postMessage(m);
});
isDisplayedPanel = true;
}
});

// A new page has been loaded.
// this event is sent with any pages that don't have SWRDevTools
port.postMessage({
type: "initialized",
type: "load",
});

window.addEventListener("message", (e: MessageEvent<DevToolsMessage>) => {
if (e.data?.type === "updated_swr_cache") {
// console.log("received", e.data.cacheData);
port.postMessage({
type: "updated_cache",
payload: e.data.payload,
});
switch (e.data?.type) {
case "initialized": {
port.postMessage(e.data);
break;
}
case "updated_swr_cache": {
if (isDisplayedPanel) {
port.postMessage(e.data);
} else {
// enqueue a message if a panel hasn't been displayed
enqueueMessage(e.data);
}
break;
}
default: {
// noop
}
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ const panels: Panel[] = [
];

type Props = {
cache: Cache;
isReady?: boolean;
cache: Cache | null;
isFixedPosition?: boolean;
};

Expand Down Expand Up @@ -56,7 +55,7 @@ const GlobalStyle = createGlobalStyle`
}
`;

export const SWRDevToolPanel = ({ cache, isReady = true }: Props) => {
export const SWRDevToolPanel = ({ cache }: Props) => {
const [activePanel, setActivePanel] = useState<Panel["key"]>("current");
const [selectedItemKey, setSelectedItemKey] = useState<ItemKey | null>(null);
return (
Expand All @@ -74,7 +73,7 @@ export const SWRDevToolPanel = ({ cache, isReady = true }: Props) => {
/>
</Header>
<PanelWrapper>
{isReady ? (
{cache !== null ? (
<Panel
cache={cache}
type={activePanel}
Expand Down
23 changes: 15 additions & 8 deletions packages/swr-devtools/src/SWRDevTools.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import React from "react";
import React, { useLayoutEffect } from "react";
import { useSWRConfig, SWRConfig, Middleware, Cache } from "swr";

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

const injected = new WeakSet();

export type DevToolsMessage = {
type: "updated_swr_cache";
payload: {
key: string;
value: any;
};
};
export type DevToolsMessage =
| {
type: "updated_swr_cache";
payload: {
key: string;
value: any;
};
}
| {
type: "initialized";
};

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

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

Expand Down

1 comment on commit ba34e6f

@vercel
Copy link

@vercel vercel bot commented on ba34e6f Sep 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.