From 0b5aad79557291f8210bab369a71a9d9516098c3 Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Sat, 21 Aug 2021 01:16:15 +0900 Subject: [PATCH 1/2] feat: stop using web_accessible_resources to inject a runtime script --- README.md | 6 ++---- examples/swr-devtools-demo/pages/_app.tsx | 8 +++----- packages/swr-devtools-extensions/manifest.json | 3 --- packages/swr-devtools-extensions/src/app.tsx | 4 ++-- .../swr-devtools-extensions/src/content.ts | 6 ------ .../swr-devtools-extensions/src/runtime.ts | 17 ----------------- packages/swr-devtools/package.json | 4 ++-- .../swr-devtools/src/components/SWRDevTool.tsx | 4 ++-- packages/swr-devtools/src/devtools-cache.ts | 18 +++++++++++++----- packages/swr-devtools/src/index.ts | 3 +-- packages/swr-devtools/src/runtime.ts | 14 ++++++++++++++ packages/swr-devtools/src/swr-cache.ts | 10 +++++----- yarn.lock | 7 ------- 13 files changed, 44 insertions(+), 60 deletions(-) delete mode 100644 packages/swr-devtools-extensions/src/runtime.ts create mode 100644 packages/swr-devtools/src/runtime.ts diff --git a/README.md b/README.md index 0c6d0f1..cc12192 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,9 @@ ```js import { cache } from "swr"; +import { launch } from "swr-devtools"; -if (typeof window !== "undefined") { - window.__SWR_DEVTOOLS__?.launch(cache); -} - +launch(cache); ``` ## Use this as a React Component diff --git a/examples/swr-devtools-demo/pages/_app.tsx b/examples/swr-devtools-demo/pages/_app.tsx index 4d39696..e6cac51 100644 --- a/examples/swr-devtools-demo/pages/_app.tsx +++ b/examples/swr-devtools-demo/pages/_app.tsx @@ -1,15 +1,13 @@ import "../styles/globals.css"; -import { SWRDevTools, createDevToolsCache } from "swr-devtools"; +import { SWRDevTools, launch } from "swr-devtools"; import { cache } from "swr"; // The way to use SWR DevTools as a Chrome extension if (typeof window !== "undefined") { - // @ts-ignore - globalThis.__SWR_DEVTOOLS__?.launch(cache); + launch(cache); } // The way to use SWR DevTools as a React Component -const devtoolsSWRCache = createDevToolsCache(cache); const DevToolsArea = () => (
( height: "400px", }} > - +
); diff --git a/packages/swr-devtools-extensions/manifest.json b/packages/swr-devtools-extensions/manifest.json index 132a321..21eb9aa 100644 --- a/packages/swr-devtools-extensions/manifest.json +++ b/packages/swr-devtools-extensions/manifest.json @@ -18,8 +18,5 @@ "js": ["content.js"], "run_at": "document_start" } - ], - "web_accessible_resources": [ - "runtime.js" ] } \ No newline at end of file diff --git a/packages/swr-devtools-extensions/src/app.tsx b/packages/swr-devtools-extensions/src/app.tsx index 0b9446e..4480ac7 100644 --- a/packages/swr-devtools-extensions/src/app.tsx +++ b/packages/swr-devtools-extensions/src/app.tsx @@ -1,7 +1,7 @@ import ReactDOM from "react-dom"; -import { SWRDevTools, createDevToolsCache } from "swr-devtools"; +import { SWRDevTools } from "swr-devtools"; -const cache = createDevToolsCache(new Map() as any); +const cache = new Map(); const render = () => { ReactDOM.render( diff --git a/packages/swr-devtools-extensions/src/content.ts b/packages/swr-devtools-extensions/src/content.ts index 1e61144..709e37f 100644 --- a/packages/swr-devtools-extensions/src/content.ts +++ b/packages/swr-devtools-extensions/src/content.ts @@ -1,9 +1,3 @@ -// FIXME: Is this injection a recommended way? -const script = document.createElement("script"); -script.src = chrome.runtime.getURL("runtime.js"); -document.documentElement.appendChild(script); -script.parentNode?.removeChild(script); - // proxy messages from applications to a background script const port = chrome.runtime.connect({ name: "content" }); window.addEventListener("message", (e) => { diff --git a/packages/swr-devtools-extensions/src/runtime.ts b/packages/swr-devtools-extensions/src/runtime.ts deleted file mode 100644 index 37c209a..0000000 --- a/packages/swr-devtools-extensions/src/runtime.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { Cache } from "swr"; -import { injectSWRCache, isMetaCache } from "swr-devtools"; - -// @ts-expect-error -window.__SWR_DEVTOOLS__ = { - launch(cache: Cache) { - injectSWRCache(cache, (key: string, value: any) => { - if (isMetaCache(key)) { - return; - } - window.postMessage( - { __SWR_DEVTOOLS__: { cacheData: { key, value } } }, - "*" - ); - }); - }, -}; diff --git a/packages/swr-devtools/package.json b/packages/swr-devtools/package.json index 1a7d1f4..0b6d882 100644 --- a/packages/swr-devtools/package.json +++ b/packages/swr-devtools/package.json @@ -11,14 +11,14 @@ "peerDependencies": { "react": "^17.0.2", "styled-components": "^5.3.0", - "swr": "^0.4.2" + "swr": "^0.5.6" }, "devDependencies": { "@types/react": "^17.0.16", "@types/styled-components": "^5.1.12", "react": "^17.0.2", "styled-components": "^5.3.0", - "swr": "^0.4.2", + "swr": "^0.5.6", "typescript": "^4.1.3" }, "dependencies": { diff --git a/packages/swr-devtools/src/components/SWRDevTool.tsx b/packages/swr-devtools/src/components/SWRDevTool.tsx index 98cf2ed..0cd1c88 100644 --- a/packages/swr-devtools/src/components/SWRDevTool.tsx +++ b/packages/swr-devtools/src/components/SWRDevTool.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; import styled, { createGlobalStyle } from "styled-components"; -import { DevToolsCache, useDevToolsCache } from "../devtools-cache"; +import { useDevToolsCache, SWRCache } from "../devtools-cache"; import { Panel } from "./Panel"; import { Tab } from "./Tab"; @@ -20,7 +20,7 @@ const panels: Panel[] = [ ]; type Props = { - cache: DevToolsCache; + cache: SWRCache; isFixedPosition?: boolean; }; diff --git a/packages/swr-devtools/src/devtools-cache.ts b/packages/swr-devtools/src/devtools-cache.ts index 3a02a9b..c2219ae 100644 --- a/packages/swr-devtools/src/devtools-cache.ts +++ b/packages/swr-devtools/src/devtools-cache.ts @@ -1,9 +1,16 @@ import { useState, useEffect } from "react"; -import type { CacheInterface } from "swr"; import { injectSWRCache, isMetaCache, SWRCacheData } from "./swr-cache"; -export type DevToolsCache = { +// This is the Cache interface for SWR v1, but this only allows a string as its key +// https://github.com/vercel/swr/blob/6e25b3b123541db5e042e5d359683575d3631df1/src/types.ts#L183 +export type SWRCache = { + get(key: string): Data | null | undefined; + set(key: string, value: Data): void; + delete(key: string): void; +}; + +type DevToolsCache = { get(key: string): Value; set(key: string, value: Value): void; delete(key: string): void; @@ -11,7 +18,7 @@ export type DevToolsCache = { subscribe(fn: (key: string, value: Value) => void): () => void; }; -export const createDevToolsCache = (cache: CacheInterface): DevToolsCache => { +const createDevToolsCache = (cache: SWRCache): DevToolsCache => { let listeners: Array<(key: string, value: any) => void> = []; const store: DevToolsCache = { get(key) { @@ -81,7 +88,7 @@ const retrieveCache = ( }; export const useDevToolsCache = ( - cache: DevToolsCache + cache: SWRCache ): [SWRCacheData[], SWRCacheData[]] => { const [cacheData, setCacheData] = useState<[SWRCacheData[], SWRCacheData[]]>([ [], @@ -89,7 +96,8 @@ export const useDevToolsCache = ( ]); useEffect(() => { - const unsubscribe = cache.subscribe((key: string, value: any) => { + const devToolsCache = createDevToolsCache(cache); + const unsubscribe = devToolsCache.subscribe((key: string, value: any) => { setCacheData(retrieveCache(key, value)); }); return () => unsubscribe(); diff --git a/packages/swr-devtools/src/index.ts b/packages/swr-devtools/src/index.ts index 61e72d7..af51bb0 100644 --- a/packages/swr-devtools/src/index.ts +++ b/packages/swr-devtools/src/index.ts @@ -1,3 +1,2 @@ export { SWRDevTools } from "./components/SWRDevTool"; -export { injectSWRCache, isMetaCache } from "./swr-cache"; -export { createDevToolsCache } from "./devtools-cache"; +export { launch } from "./runtime"; diff --git a/packages/swr-devtools/src/runtime.ts b/packages/swr-devtools/src/runtime.ts new file mode 100644 index 0000000..82452bf --- /dev/null +++ b/packages/swr-devtools/src/runtime.ts @@ -0,0 +1,14 @@ +import { injectSWRCache, isMetaCache } from "./swr-cache"; +import { SWRCache } from "./devtools-cache"; + +export const launch = (cache: SWRCache) => { + injectSWRCache(cache, (key: string, value: any) => { + if (isMetaCache(key)) { + return; + } + window.postMessage( + { __SWR_DEVTOOLS__: { cacheData: { key, value } } }, + "*" + ); + }); +}; diff --git a/packages/swr-devtools/src/swr-cache.ts b/packages/swr-devtools/src/swr-cache.ts index 0be6c31..7664092 100644 --- a/packages/swr-devtools/src/swr-cache.ts +++ b/packages/swr-devtools/src/swr-cache.ts @@ -1,4 +1,4 @@ -import type { CacheInterface } from "swr"; +import { SWRCache } from "./devtools-cache"; export type SWRCacheData = { id: number; @@ -11,7 +11,7 @@ export type SWRCacheData = { }; export const injectSWRCache = ( - cache: CacheInterface, + cache: SWRCache, watcher: (key: string, value: any) => void ): void => { // intercept operations modifying the cache store @@ -30,18 +30,18 @@ export const injectSWRCache = ( export const isMetaCache = (key: string) => { return ( // ctx and len are keys used in use-swr-infinite - /^(?:validating|err|context|size)@/.test(key) || + /^(?:validating|err|ctx|context|size)@/.test(key) || // v1 (beta) /^\$(?:req|err|ctx|len)\$/.test(key) ); }; export const isInfiniteCache = (key: string) => { - return /^arg@"many"@"/.test(key); + return /^arg@"(many|inf)"@"/.test(key); }; export const getInfiniteCacheKey = (key: string) => { // TODO: support v1 style cache keys - const match = key.match(/^arg@"many"@"(?.*)?"/); + const match = key.match(/^arg@"(many|inf)"@"(?.*)?"/); return match?.groups?.cacheKey ?? key; }; diff --git a/yarn.lock b/yarn.lock index e6e5ef9..02d7dce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4473,13 +4473,6 @@ supports-color@^8.0.0: dependencies: has-flag "^4.0.0" -swr@^0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/swr/-/swr-0.4.2.tgz#4a9ed5e9948088af145c79d716d294cb99712a29" - integrity sha512-SKGxcAfyijj/lE5ja5zVMDqJNudASH3WZPRUakDVOePTM18FnsXgugndjl9BSRwj+jokFCulMDe7F2pQL+VhEw== - dependencies: - dequal "2.0.2" - swr@^0.5.6: version "0.5.6" resolved "https://registry.yarnpkg.com/swr/-/swr-0.5.6.tgz#70bfe9bc9d7ac49a064be4a0f4acf57982e55a31" From 40795dba659dbdbc883c199b59a318d9ad7c146d Mon Sep 17 00:00:00 2001 From: Toru Kobayashi Date: Tue, 24 Aug 2021 22:48:43 +0900 Subject: [PATCH 2/2] fix: sync cache data when opening a devtool panel --- .../swr-devtools-extensions/src/background.ts | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/packages/swr-devtools-extensions/src/background.ts b/packages/swr-devtools-extensions/src/background.ts index 95b4345..e76b58e 100644 --- a/packages/swr-devtools-extensions/src/background.ts +++ b/packages/swr-devtools-extensions/src/background.ts @@ -1,15 +1,36 @@ // background.js -let panelPort: chrome.runtime.Port | null; +let panelPort: 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); +}; + chrome.runtime.onConnect.addListener((port) => { // A port between a content page if (port.name === "content") { port.onMessage.addListener((message) => { console.log("sent message from content to panel", message); - panelPort?.postMessage(message); + if (panelPort === null) { + enqueueMessage(message); + } else { + flushQueuedMessages(); + panelPort.postMessage(message); + } }); // A port between the SWR panel in devtools } else if (port.name === "panel") { panelPort = port; + flushQueuedMessages(); panelPort.onDisconnect.addListener(() => { panelPort = null; });