-
-
Notifications
You must be signed in to change notification settings - Fork 47
feat: create event bus server + client communication for devtools #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| import { DevtoolsClient } from '@tanstack/devtools/client' | ||
|
|
||
| const devtoolsClient = new DevtoolsClient() | ||
|
|
||
| devtoolsClient.connect() | ||
|
|
||
| export { devtoolsClient } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
create a client connection to the server to listen to incoming events
More templates
@tanstack/devtools
@tanstack/devtools-event-bus
@tanstack/devtools-event-client
@tanstack/react-devtools
@tanstack/solid-devtools
commit: |
| devtoolsClient.onAll((event) => { | ||
| console.log('Received message:', event) | ||
| setEvents((prev) => [...prev, event]) | ||
| }) | ||
| devtoolsClient.emit({ | ||
| type: 'init', | ||
| payload: { | ||
| title: 'Client Plugin Initialized', | ||
| description: 'Listening for events', | ||
| }, | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
listens to events from client/server
| <p>Devtools Client is connected.</p> | ||
| <button | ||
| onClick={() => | ||
| devtoolsClient.emit({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
emits the event to server/client listeners
| import { z } from 'zod' | ||
| const devtoolsServer = new DevtoolsServer() | ||
|
|
||
| devtoolsServer.start() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
start the dev server to listen to events
| devtoolsServer.on('click-event', (payload) => { | ||
| console.log('Click event received:', payload) | ||
| }) | ||
|
|
||
| devtoolsServer.onAll((e) => { | ||
| console.log('All events:', e) | ||
| }) | ||
|
|
||
| setInterval(() => { | ||
| console.log('Emitting server event...') | ||
| devtoolsServer.emit({ | ||
| type: 'server-event', | ||
| payload: { | ||
| title: 'Server Event', | ||
| description: 'This is a custom event emitted by the server.', | ||
| }, | ||
| }) | ||
| }, 5000) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
send/listen to client/server events
| const eventMap = { | ||
| 'query-devtools:test': z.object({ | ||
| title: z.string(), | ||
| description: z.string(), | ||
| }), | ||
| 'query-devtools:init': z.object({ | ||
| title: z.string(), | ||
| description: z.string(), | ||
| }), | ||
| 'query-devtools:b': z.object({ | ||
| title: z.string(), | ||
| description: z.string(), | ||
| }), | ||
| } satisfies EventMap<'query-devtools'> | ||
|
|
||
| class QueryDevtoolsPlugin extends DevtoolsPlugin<typeof eventMap> { | ||
| constructor() { | ||
| super({ | ||
| pluginId: 'query-devtools', | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| const plugin = new QueryDevtoolsPlugin() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
potential plugin API right here, WDYT?
| }), | ||
| } satisfies EventMap<'query-devtools'> | ||
|
|
||
| class QueryDevtoolsPlugin extends DevtoolsPlugin<typeof eventMap> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any typescript wizards who know how to infer the types automatically without providing type args by passing it into the constructor maybe and still constraining the keys to start with the pluginId?
| plugin.onAll((e) => { | ||
| if (e.type === 'query-devtools:test') { | ||
| console.log('Received query-devtools:test event:', e.payload) | ||
| } | ||
| }) | ||
| plugin.on('query-devtools:test', (e) => { | ||
| e.payload | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fully type-safe
| payload: TPayload | ||
| } | ||
|
|
||
| export class DevtoolsClient { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
connects to the server, sends events there, also listens to the events from the server, uses websockets, falls back to SSE
| TEventMap extends Record<string, any>, | ||
| TPluginId extends string = TEventMap extends Record<infer P, any> | ||
| ? P extends `${infer Id}:${string}` | ||
| ? Id | ||
| : never | ||
| : never, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would appreciate some help on auto-inferring these without providing type-args
| var __EVENT_TARGET__: EventTarget | null | ||
| } | ||
|
|
||
| export class DevtoolsServer { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
core of the event-bus, emits events to server listeners via EventTarget (might change it to WS instead) and to the client via WS and falls back to SSE.
|
Here's chatgpt's feedback https://chatgpt.com/share/6890e13d-d5ec-800c-a58a-a36afcb640e7 |
|
Thanks, it made some good points 🙏 |
|
Really excited by this! One thought I had was that it could be modelled on MessageChannel / MessagePort api (https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API), it then may be possible to make it plug-and-play with other tools that work with that interface. For most use cases the event emitter is perfect, just update the state in the devtools, but sometimes you need a RPC type mechanism (trigger some action within the page and read the results). If it was models on the message port api, it may be possible to use it with ComLink to implement RPC: https://github.com/GoogleChromeLabs/comlink For the DB devtools I intend to bake in an event bus from the start so that we can make a version that works with react native in future. |
|
Interesting, I need to check this API out, do you have some advanced examples to get a feeling for what's possible? |
…tools into feat/bus-connection
|
TODO:
|
…tools into feat/bus-connection
This PR does the following:
EventClientinterface from@tanstack/devtools-event-client.@tanstack/devtools-event-busand@tanstack/detools-event-client