Skip to content

Commit 6b49184

Browse files
committed
migrate to event client
1 parent 05fccc1 commit 6b49184

File tree

13 files changed

+167
-137
lines changed

13 files changed

+167
-137
lines changed

packages/react-router-devtools/package.json

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,7 @@
5959
"require": "./dist/client.css"
6060
}
6161
},
62-
"files": [
63-
"dist"
64-
],
62+
"files": ["dist"],
6563
"repository": {
6664
"type": "git",
6765
"url": "git+https://github.com/forge-42/react-router-devtools.git"
@@ -140,8 +138,8 @@
140138
"@radix-ui/react-accordion": "^1.2.2",
141139
"@radix-ui/react-select": "^2.1.5",
142140
"@tanstack/devtools-event-client": "^0.3.3",
143-
"@tanstack/devtools-vite": "^0.3.8",
144-
"@tanstack/react-devtools": "^0.7.7",
141+
"@tanstack/devtools-vite": "^0.3.11",
142+
"@tanstack/react-devtools": "^0.8.0",
145143
"beautify": "^0.0.8",
146144
"bippy": "^0.3.7",
147145
"chalk": "5.4.1",
@@ -160,4 +158,4 @@
160158
"@rollup/rollup-darwin-arm64": "^4.32.1",
161159
"@rollup/rollup-linux-x64-gnu": "^4.32.1"
162160
}
163-
}
161+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import type { SVGProps } from "react"
2+
3+
interface LogoProps extends SVGProps<SVGSVGElement> {
4+
className?: string
5+
}
6+
7+
const Logo = ({ className, style }: LogoProps) => {
8+
return (
9+
<svg style={style} className={className} viewBox="0 0 602 360" fill="none" xmlns="http://www.w3.org/2000/svg">
10+
<title>Logo</title>
11+
<path
12+
d="M481.36 180C481.36 196.572 474.638 211.572 463.757 222.42C452.875 233.28 437.845 240 421.24 240C404.635 240 389.605 246.708 378.735 257.568C367.853 268.428 361.12 283.428 361.12 300C361.12 316.572 354.398 331.572 343.517 342.42C332.635 353.28 317.605 360 301 360C284.395 360 269.365 353.28 258.495 342.42C247.613 331.572 240.88 316.572 240.88 300C240.88 283.428 247.613 268.428 258.495 257.568C269.365 246.708 284.395 240 301 240C317.605 240 332.635 233.28 343.517 222.42C354.398 211.572 361.12 196.572 361.12 180C361.12 146.856 334.21 120 301 120C284.395 120 269.365 113.28 258.495 102.42C247.613 91.572 240.88 76.572 240.88 60C240.88 43.428 247.613 28.428 258.495 17.568C269.365 6.708 284.395 0 301 0C334.21 0 361.12 26.856 361.12 60C361.12 76.572 367.853 91.572 378.735 102.42C389.605 113.28 404.635 120 421.24 120C454.45 120 481.36 146.856 481.36 180Z"
13+
fill="#F44250"
14+
/>
15+
<path
16+
d="M240.88 180C240.88 146.862 213.963 120 180.76 120C147.557 120 120.64 146.862 120.64 180C120.64 213.137 147.557 240 180.76 240C213.963 240 240.88 213.137 240.88 180Z"
17+
fill="white"
18+
/>
19+
<path
20+
d="M120.64 300C120.64 266.863 93.7233 240 60.5199 240C27.3165 240 0.399902 266.863 0.399902 300C0.399902 333.138 27.3165 360 60.5199 360C93.7233 360 120.64 333.138 120.64 300Z"
21+
fill="white"
22+
/>
23+
<path
24+
d="M601.6 300C601.6 266.863 574.683 240 541.48 240C508.277 240 481.36 266.863 481.36 300C481.36 333.138 508.277 360 541.48 360C574.683 360 601.6 333.138 601.6 300Z"
25+
fill="white"
26+
/>
27+
</svg>
28+
)
29+
}
30+
31+
export { Logo }

packages/react-router-devtools/src/client/context/requests/request-context.tsx

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { type ReactNode, createContext, useCallback, useContext, useEffect, useState } from "react"
2+
import { eventClient } from "../../../shared/event-client"
23
import type { RequestEvent } from "../../../shared/request-event"
34

45
const RequestContext = createContext<{
@@ -10,24 +11,21 @@ const requestMap = new Map<string, RequestEvent>()
1011

1112
export const RequestProvider = ({ children }: { children: ReactNode }) => {
1213
const [requests, setRequests] = useState<RequestEvent[]>([])
13-
const setNewRequests = useCallback((payload: string) => {
14-
const requests = JSON.parse(payload)
15-
const newRequests = Array.isArray(requests) ? requests : [requests]
16-
for (const req of newRequests) {
17-
requestMap.set(req.id + req.startTime, req)
18-
import.meta.hot?.send("remove-event", { ...req, fromClient: true })
19-
}
14+
15+
const handleRequestEvent = useCallback((event: { payload: RequestEvent }) => {
16+
const req = event.payload
17+
requestMap.set(req.id + req.startTime, req)
18+
2019
setRequests(Array.from(requestMap.values()))
2120
}, [])
21+
2222
useEffect(() => {
23-
import.meta.hot?.send("get-events")
24-
import.meta.hot?.on("get-events", setNewRequests)
25-
import.meta.hot?.on("request-event", setNewRequests)
23+
const unsubscribeRequestEvent = eventClient.on("request-event", handleRequestEvent)
24+
2625
return () => {
27-
import.meta.hot?.off?.("get-events", setNewRequests)
28-
import.meta.hot?.off?.("request-event", setNewRequests)
26+
unsubscribeRequestEvent()
2927
}
30-
}, [setNewRequests])
28+
}, [handleRequestEvent])
3129

3230
const removeAllRequests = useCallback(() => {
3331
setRequests([])

packages/react-router-devtools/src/client/embedded-dev-tools.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { Tabs } from "./layout/Tabs.js"
1010
import type { ReactRouterDevtoolsProps } from "./react-router-dev-tools.js"
1111
// Import to ensure global reset styles are injected
1212
import "./styles/use-styles.js"
13+
import { RequestProvider } from "./context/requests/request-context.js"
1314
import { REACT_ROUTER_DEV_TOOLS } from "./utils/storage.js"
1415

1516
export interface EmbeddedDevToolsProps extends ReactRouterDevtoolsProps {
@@ -59,7 +60,9 @@ const EmbeddedDevTools = ({ plugins, mainPanelClassName, className }: EmbeddedDe
5960

6061
return (
6162
<RDTContextProvider>
62-
<Embedded mainPanelClassName={mainPanelClassName} className={className} plugins={plugins} />
63+
<RequestProvider>
64+
<Embedded mainPanelClassName={mainPanelClassName} className={className} plugins={plugins} />
65+
</RequestProvider>
6366
</RDTContextProvider>
6467
)
6568
}

packages/react-router-devtools/src/client/hof.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import type { ClientActionFunctionArgs, ClientLoaderFunctionArgs, LinksFunction } from "react-router"
22
import { convertBigIntToString } from "../shared/bigint-util"
3+
import { eventClient } from "../shared/event-client"
34
import type { RequestEvent } from "../shared/request-event"
45

56
const sendEventToDevServer = (req: RequestEvent) => {
67
if (req.data) {
78
req.data = convertBigIntToString(req.data)
89
}
9-
import.meta.hot?.send("request-event", req)
10+
eventClient.emit("request-event", req)
1011
}
1112

1213
const analyzeClientLoaderOrAction = (

packages/react-router-devtools/src/client/init/root.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { TanStackDevtools } from "@tanstack/react-devtools"
2+
import { Logo } from "../components/logo.js"
23
import type { RdtClientConfig } from "../context/RDTContext.js"
3-
import { RequestProvider } from "../context/requests/request-context.js"
44
import { EmbeddedDevTools } from "../embedded-dev-tools.js"
55
import type { ReactRouterDevtoolsProps } from "../react-router-dev-tools.js"
6+
import { useStyles } from "../styles/use-styles.js"
67
import { hydrationDetector } from "./hydration.js"
7-
import triggerImage from "./trigger.svg"
88

99
export const defineClientConfig = (config: RdtClientConfig) => config
1010

@@ -18,16 +18,25 @@ export const withViteDevTools = (Component: any, _config?: ReactRouterDevtoolsPr
1818
hydrationDetector()
1919
// biome-ignore lint/suspicious/noExplicitAny: we don't care about the type here as we spread it below
2020
function AppWithDevTools(props: any) {
21+
const { styles } = useStyles()
2122
return (
22-
<RequestProvider>
23+
<>
2324
<Component {...props} />
2425
<TanStackDevtools
2526
config={{
26-
triggerImage,
27+
customTrigger: (
28+
<div data-testid="react-router-devtools-trigger" className={styles.tanstackTrigger.container}>
29+
<Logo className={styles.tanstackTrigger.logo} />
30+
</div>
31+
),
32+
}}
33+
eventBusConfig={{
34+
connectToServerBus: true,
35+
debug: true,
2736
}}
2837
plugins={[{ name: "React Router Devtools", render: <EmbeddedDevTools /> }]}
2938
/>
30-
</RequestProvider>
39+
</>
3140
)
3241
}
3342
return AppWithDevTools(props)

packages/react-router-devtools/src/client/styles/use-styles.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2098,6 +2098,42 @@ const stylesFactory = (theme: "light" | "dark") => {
20982098
background-image: linear-gradient(to right, #f3f4f6, #d1d5db) !important;
20992099
`,
21002100
},
2101+
2102+
// TanStack Devtools Trigger
2103+
tanstackTrigger: {
2104+
container: css`
2105+
2106+
height: 3rem;
2107+
width: 3rem;
2108+
cursor: pointer;
2109+
padding: 0.5rem;
2110+
background-color: #212121;
2111+
display: flex;
2112+
align-items: center;
2113+
justify-content: center;
2114+
border-radius: 9999px;
2115+
transition: all 0.2s;
2116+
2117+
&:hover {
2118+
cursor: pointer;
2119+
outline-offset: 2px;
2120+
outline: 2px solid #212121;
2121+
}
2122+
`,
2123+
logo: css`
2124+
outline: none;
2125+
width: 100%;
2126+
height: 100%;
2127+
margin-top: -0.25rem;
2128+
border-radius: 9999px;
2129+
transition: all 200ms;
2130+
overflow: visible;
2131+
2132+
&:focus {
2133+
outline: none;
2134+
}
2135+
`,
2136+
},
21012137
}
21022138
}
21032139

packages/react-router-devtools/src/context/tracing.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { eventClient } from "../shared/event-client"
12
import type { AllDataFunctionArgs, NetworkRequestType, RequestEvent } from "../shared/request-event"
23
import { sendEvent } from "../shared/send-event"
34

@@ -6,9 +7,7 @@ export const traceEvent =
67
// biome-ignore lint/suspicious/noExplicitAny: can be any type
78
async <T>(name: string, event: (...args: any) => T) => {
89
const isServer = type === "action" || type === "loader"
9-
const emitEventFunction = isServer
10-
? sendEvent
11-
: (data: RequestEvent) => import.meta.hot?.send("request-event", data)
10+
const emitEventFunction = isServer ? sendEvent : (data: RequestEvent) => eventClient.emit("request-event", data)
1211
const startTime = Date.now()
1312
emitEventFunction({
1413
type: "custom-event",
@@ -34,7 +33,7 @@ export const traceEvent =
3433

3534
export const traceStart = (type: NetworkRequestType, args: AllDataFunctionArgs) => (name: string) => {
3635
const isServer = type === "action" || type === "loader"
37-
const emitEventFunction = isServer ? sendEvent : (data: RequestEvent) => import.meta.hot?.send("request-event", data)
36+
const emitEventFunction = isServer ? sendEvent : (data: RequestEvent) => eventClient.emit("request-event", data)
3837
const startTime = Date.now()
3938
emitEventFunction({
4039
type: "custom-event",
@@ -51,9 +50,7 @@ export const traceEnd =
5150
(type: NetworkRequestType, args: AllDataFunctionArgs) =>
5251
<T>(name: string, startTime: number, data?: T) => {
5352
const isServer = type === "action" || type === "loader"
54-
const emitEventFunction = isServer
55-
? sendEvent
56-
: (data: RequestEvent) => import.meta.hot?.send("request-event", data)
53+
const emitEventFunction = isServer ? sendEvent : (data: RequestEvent) => eventClient.emit("request-event", data)
5754

5855
emitEventFunction({
5956
type: "custom-event",
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { EventClient } from "@tanstack/devtools-event-client"
2+
import type { RequestEvent } from "./request-event"
3+
4+
interface EventMap {
5+
"rdt:request-event": RequestEvent
6+
"rdt:get-events": RequestEvent[] // Both request (empty array) and response (array of events)
7+
"rdt:remove-event": { id: string; startTime: number; fromClient?: boolean }
8+
}
9+
10+
export const eventClient = new EventClient<EventMap>({
11+
pluginId: "rdt",
12+
})
Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,6 @@
1-
import { bigIntReplacer } from "./bigint-util"
1+
import { eventClient } from "./event-client"
22
import type { RequestEvent } from "./request-event"
33

44
export const sendEvent = (event: RequestEvent) => {
5-
if (typeof process === "undefined") {
6-
return
7-
}
8-
const port = process.rdt_port
9-
10-
if (port) {
11-
fetch(`http://localhost:${port}/__rrdt`, {
12-
method: "POST",
13-
body: JSON.stringify({ routine: "request-event", ...event }, bigIntReplacer),
14-
})
15-
.then(async (res) => {
16-
// avoid memory leaks
17-
if (res.ok) {
18-
await res.text()
19-
}
20-
})
21-
.catch(() => {})
22-
}
5+
eventClient.emit("request-event", event)
236
}

0 commit comments

Comments
 (0)