-
Notifications
You must be signed in to change notification settings - Fork 17
✨ (devtools) [NO-ISSUE]: DMK devtools for RN & web apps #1163
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
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
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.
Pull request overview
This PR introduces a comprehensive developer tools system for the Device Management Kit (DMK) to replace the deprecated Flipper integration. The implementation creates a flexible, bi-directional communication bridge between client applications and a dashboard interface.
Key changes:
- Removed deprecated Flipper-based devtools packages and integration code
- Added 7 new devtools packages implementing a modular WebSocket-based architecture
- Created platform-specific implementations for React Native (Rozenite) and web/Electron
- Integrated devtools into sample and mobile applications
Reviewed changes
Copilot reviewed 117 out of 132 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/devtools-core/* | Core types, interfaces, and DevToolsLogger implementation |
| packages/devtools-websocket-*/ | WebSocket server, connector, and common utilities for bidirectional communication |
| packages/devtools-ui/* | React-based dashboard UI with logger and debugging screens |
| packages/devtools-rozenite/* | Rozenite integration for React Native applications |
| apps/devtools/* | Electron application hosting the dashboard and WebSocket server |
| apps/sample/* | Updated to use new WebSocket-based devtools |
| apps/mobile/* | Integrated Rozenite devtools for React Native |
| packages/flipper-plugin-client/* | Deprecated Flipper code removed |
| pnpm-workspace.yaml | Added Electron and Vite dependencies to catalog |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
packages/devtools-rozenite/src/react-native/ClientRozeniteConnector.ts
Outdated
Show resolved
Hide resolved
packages/devtools-rozenite/src/react-native/ClientRozeniteConnector.ts
Outdated
Show resolved
Hide resolved
4303a3a to
09064ca
Compare
c9ab17c to
3dde754
Compare
3dde754 to
819a09a
Compare
819a09a to
2c06815
Compare
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.
Pull request overview
Copilot reviewed 116 out of 131 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
2c06815 to
df02807
Compare
df02807 to
0a363be
Compare
packages/devtools-websocket-connector/src/DevtoolsWebSocketConnector.ts
Outdated
Show resolved
Hide resolved
| * STATIC METHODS | ||
| */ | ||
| static instance: RozeniteConnector | null = null; | ||
| static getInstance(): RozeniteConnector { |
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.
[ASK] Why do you create a singleton here? You cannot use a DI library?
| * STATIC METHODS | ||
| */ | ||
| static instance: DevtoolsWebSocketConnector | null = null; | ||
| static getInstance(): DevtoolsWebSocketConnector { |
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.
[ASK] Same
| * STATIC METHODS | ||
| */ | ||
| static instance: DevtoolsWebSocketConnector | null = null; | ||
| static getInstance(): DevtoolsWebSocketConnector { |
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.
[ASK] In. fact I don't not understand how you switch between different impl of Connector because of the usage of the singleton pattern
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.
@smartine-ledger regarding this comment and the two comments above:
The Connector interface exists so dev tools modules (for instance DevToolsLogger) can accept an instance of a Connector, but the client picks one based on their platform. They're not interchangeable at runtime, they're alternative implementations for different environments:
- React Native apps:
RozeniteConnector - Web apps:
DevToolsWebSocketConnector
The singleton serves a specific purpose for the developer experience in client apps: The goal is to allow any client app to very easily integrate the DMK devtools without having to setup a dependency injection system.
Why we need it:
The Connector instance needs to be:
- Initialized with platform-specific logic (for instance,
RozeniteConnectorneeds to receive aRozeniteDevToolsClient,DevtoolsWebSocketConnectorneeds a URL to connect to) - Passed to a devtools module (for instance
DevToolsLogger) which is then passed to the DMK builder.
These two actions often happen in very different parts of a client application, and not necessarily in that order. The singleton pattern allows both places to access the same instance without requiring a DI setup. The initialisation logic inside the connectors, along with the ReplaySubjects ensures that the two actions can happen in any order.
For the same reason, using a DI lib here does not make sense because the DI would have to be done in the client app, not in the DMK.
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.
I don't understand why the client needs to setup a DI if you provide a single entry point to your devtool (ex : buildDevToolLogger()) and implement in your side all the logic of the creation of the differents objects through a DI. This will allow to make the package easier to maintain and easily scalable but ok. Let's keep the code unchanged for the moment
| url: string; | ||
| }; | ||
|
|
||
| export class DevtoolsWebSocketConnector implements Connector { |
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.
[COMMENT] you can keep it like this for the moment but this class seems to do a lot of thing (initialise the connection / handle the internal state of the connection / format the message through a JSON lib
| client: { | ||
| server: null, | ||
| connection: null, | ||
| messageBuffer: new ReplaySubject(), | ||
| messageBufferSubscription: null, | ||
| }, | ||
| dashboard: { | ||
| server: null, | ||
| connection: null, | ||
| messageBuffer: new ReplaySubject(), | ||
| messageBufferSubscription: null, | ||
| }, | ||
| }; |
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.
[ASK] One class which handles two different kind of connection? 🤔
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.
The class has a single responsibility: acting as a message bridge between client and dashboard.
The two connections are fundamentally coupled: messages flow between them, and disconnection of one affects the buffering logic of the other.
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.
Ok. IMHO it can be simplify but let's keep this way for the moment and we will see in the future if we need to handle additional logic 😉
For some reason in this branch we detect TS issues that were previously undetected
453ce32 to
db0d011
Compare
db0d011 to
cf223c9
Compare
| client: { | ||
| server: null, | ||
| connection: null, | ||
| messageBuffer: new ReplaySubject(), | ||
| messageBufferSubscription: null, | ||
| }, | ||
| dashboard: { | ||
| server: null, | ||
| connection: null, | ||
| messageBuffer: new ReplaySubject(), | ||
| messageBufferSubscription: null, | ||
| }, | ||
| }; |
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.
Ok. IMHO it can be simplify but let's keep this way for the moment and we will see in the future if we need to handle additional logic 😉
| * STATIC METHODS | ||
| */ | ||
| static instance: DevtoolsWebSocketConnector | null = null; | ||
| static getInstance(): DevtoolsWebSocketConnector { |
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.
I don't understand why the client needs to setup a DI if you provide a single entry point to your devtool (ex : buildDevToolLogger()) and implement in your side all the logic of the creation of the differents objects through a DI. This will allow to make the package easier to maintain and easily scalable but ok. Let's keep the code unchanged for the moment
📝 Description
This PR introduces a new way to implement developer tools for the DMK.
There was already an existing implementation relying on Flipper, but as it is deprecated, we need a new solution.
For this new implementation, I chose to not depend on any third party, but keep the door open in case some frameworks can help us. It's the case of Rozenite which is a developer tools platform for React Native apps.
The core of the work done here is the building of a bi-directional communication bridge between a client app (hosting the DMK) and an app called "Dashboard". It's a platform on top of which we can build actual developer tools that will have their UI in the "Dashboard" app.
There are two "dashboard app" implementations:
In terms of features, for now the devtools only support displaying the logs of the DMK.
More features will come, for instance:
So the work is structured in several modules:
packages/devtools-core:DevToolsLoggerwhich can be injected in DeviceManagementKitBuilder and will relay all DMK logs to the devtools dashboard.packages/devtools-rozenite:packages/devtools-uipackages/devtools-websocket-commonpackages/devtools-websocket-connectorConnectorthat is able to talk with the websocket serverpackages/devtools-websocket-serverapps/devtoolsdevtools-websocket-serveras well asdevtools-uiso that a client app using thedevtools-websocket-connectorcan connect to it and have some working developer tools.Demo
Rozenite
rozenite.devtools.mp4
WebSocket + Electron
Screen.Recording.2025-12-01.at.20.49.56.mp4
ℹ️ NB: >8k lines modified, but >5k are due to the addition of several packages and changes in the pnpm lockfile related to the addition of an Electron project
❓ Context
✅ Checklist
Pull Requests must pass CI checks and undergo code review. Set the PR as Draft if it is not yet ready for review.
🧐 Checklist for the PR Reviewers