diff --git a/packages/react-devtools-core/README.md b/packages/react-devtools-core/README.md
index b0f0e98191b35..8ccdc0f4902e0 100644
--- a/packages/react-devtools-core/README.md
+++ b/packages/react-devtools-core/README.md
@@ -14,35 +14,41 @@ If you are building a non-browser-based React renderer, you can use the backend
```js
if (process.env.NODE_ENV !== 'production') {
- const { connectToDevTools } = require("react-devtools-core");
+ const { initialize, connectToDevTools } = require("react-devtools-core");
+ initialize(settings);
// Must be called before packages like react or react-native are imported
- connectToDevTools({
- ...config
- });
+ connectToDevTools({...config});
}
```
> **NOTE** that this API (`connectToDevTools`) must be (1) run in the same context as React and (2) must be called before React packages are imported (e.g. `react`, `react-dom`, `react-native`).
+### `initialize` arguments
+| Argument | Description |
+|------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `settings` | Optional. If not specified, or received as null, then default settings are going to be applied: appending component stacks to error messages and displaying inline errors and warnings.
Can be plain object or a Promise that resolves with the plain object with [these boolean fields](https://github.com/facebook/react/blob/20cec76c44f77e74b3a85225fecab5a431cd986f/packages/react-devtools-shared/src/backend/types.js#L531-L536). If Promise rejects, the console will not be patched and some console features from React DevTools will not work. |
+
### `connectToDevTools` options
-| Prop | Default | Description |
-|---|---|---|
-| `host` | `"localhost"` | Socket connection to frontend should use this host. |
-| `isAppActive` | | (Optional) function that returns true/false, telling DevTools when it's ready to connect to React. |
-| `port` | `8097` | Socket connection to frontend should use this port. |
-| `resolveRNStyle` | | (Optional) function that accepts a key (number) and returns a style (object); used by React Native. |
-| `retryConnectionDelay` | `200` | Delay (ms) to wait between retrying a failed Websocket connection |
-| `useHttps` | `false` | Socket connection to frontend should use secure protocol (wss). |
-| `websocket` | | Custom `WebSocket` connection to frontend; overrides `host` and `port` settings. |
+| Prop | Default | Description |
+|------------------------|---------------|---------------------------------------------------------------------------------------------------------------------------|
+| `host` | `"localhost"` | Socket connection to frontend should use this host. |
+| `isAppActive` | | (Optional) function that returns true/false, telling DevTools when it's ready to connect to React. |
+| `port` | `8097` | Socket connection to frontend should use this port. |
+| `resolveRNStyle` | | (Optional) function that accepts a key (number) and returns a style (object); used by React Native. |
+| `retryConnectionDelay` | `200` | Delay (ms) to wait between retrying a failed Websocket connection |
+| `useHttps` | `false` | Socket connection to frontend should use secure protocol (wss). |
+| `websocket` | | Custom `WebSocket` connection to frontend; overrides `host` and `port` settings. |
+| `onSettingsUpdated` | | A callback that will be called when the user updates the settings in the UI. You can use it for persisting user settings. | |
### `connectWithCustomMessagingProtocol` options
-| Prop | Description |
-|-----------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| `onSubscribe` | Function, which receives listener (function, with a single argument) as an argument. Called when backend subscribes to messages from the other end (frontend). |
-| `onUnsubscribe` | Function, which receives listener (function) as an argument. Called when backend unsubscribes to messages from the other end (frontend). |
-| `onMessage` | Function, which receives 2 arguments: event (string) and payload (any). Called when backend emits a message, which should be sent to the frontend. |
+| Prop | Description |
+|---------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `onSubscribe` | Function, which receives listener (function, with a single argument) as an argument. Called when backend subscribes to messages from the other end (frontend). |
+| `onUnsubscribe` | Function, which receives listener (function) as an argument. Called when backend unsubscribes to messages from the other end (frontend). |
+| `onMessage` | Function, which receives 2 arguments: event (string) and payload (any). Called when backend emits a message, which should be sent to the frontend. |
+| `onSettingsUpdated` | A callback that will be called when the user updates the settings in the UI. You can use it for persisting user settings. |
Unlike `connectToDevTools`, `connectWithCustomMessagingProtocol` returns a callback, which can be used for unsubscribing the backend from the global DevTools hook.
diff --git a/packages/react-devtools-core/src/backend.js b/packages/react-devtools-core/src/backend.js
index 84f537e875d00..314358e7ed948 100644
--- a/packages/react-devtools-core/src/backend.js
+++ b/packages/react-devtools-core/src/backend.js
@@ -20,7 +20,10 @@ import type {
ComponentFilter,
Wall,
} from 'react-devtools-shared/src/frontend/types';
-import type {DevToolsHook} from 'react-devtools-shared/src/backend/types';
+import type {
+ DevToolsHook,
+ DevToolsHookSettings,
+} from 'react-devtools-shared/src/backend/types';
import type {ResolveNativeStyle} from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor';
type ConnectOptions = {
@@ -32,12 +35,9 @@ type ConnectOptions = {
retryConnectionDelay?: number,
isAppActive?: () => boolean,
websocket?: ?WebSocket,
+ onSettingsUpdated?: (settings: DevToolsHookSettings) => void,
};
-installHook(window);
-
-const hook: ?DevToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
-
let savedComponentFilters: Array =
getDefaultComponentFilters();
@@ -52,11 +52,21 @@ function debug(methodName: string, ...args: Array) {
}
}
+export function initialize(
+ maybeSettingsOrSettingsPromise?:
+ | DevToolsHookSettings
+ | Promise,
+) {
+ installHook(window, maybeSettingsOrSettingsPromise);
+}
+
export function connectToDevTools(options: ?ConnectOptions) {
+ const hook: ?DevToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
if (hook == null) {
// DevTools didn't get injected into this page (maybe b'c of the contentType).
return;
}
+
const {
host = 'localhost',
nativeStyleEditorValidAttributes,
@@ -66,6 +76,7 @@ export function connectToDevTools(options: ?ConnectOptions) {
resolveRNStyle = (null: $FlowFixMe),
retryConnectionDelay = 2000,
isAppActive = () => true,
+ onSettingsUpdated,
} = options || {};
const protocol = useHttps ? 'wss' : 'ws';
@@ -160,7 +171,14 @@ export function connectToDevTools(options: ?ConnectOptions) {
// TODO (npm-packages) Warn if "isBackendStorageAPISupported"
// $FlowFixMe[incompatible-call] found when upgrading Flow
const agent = new Agent(bridge);
+ if (onSettingsUpdated != null) {
+ agent.addListener('updateHookSettings', onSettingsUpdated);
+ }
agent.addListener('shutdown', () => {
+ if (onSettingsUpdated != null) {
+ agent.removeListener('updateHookSettings', onSettingsUpdated);
+ }
+
// If we received 'shutdown' from `agent`, we assume the `bridge` is already shutting down,
// and that caused the 'shutdown' event on the `agent`, so we don't need to call `bridge.shutdown()` here.
hook.emit('shutdown');
@@ -290,6 +308,7 @@ type ConnectWithCustomMessagingOptions = {
onMessage: (event: string, payload: any) => void,
nativeStyleEditorValidAttributes?: $ReadOnlyArray,
resolveRNStyle?: ResolveNativeStyle,
+ onSettingsUpdated?: (settings: DevToolsHookSettings) => void,
};
export function connectWithCustomMessagingProtocol({
@@ -298,7 +317,9 @@ export function connectWithCustomMessagingProtocol({
onMessage,
nativeStyleEditorValidAttributes,
resolveRNStyle,
+ onSettingsUpdated,
}: ConnectWithCustomMessagingOptions): Function {
+ const hook: ?DevToolsHook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
if (hook == null) {
// DevTools didn't get injected into this page (maybe b'c of the contentType).
return;
@@ -334,7 +355,14 @@ export function connectWithCustomMessagingProtocol({
}
const agent = new Agent(bridge);
+ if (onSettingsUpdated != null) {
+ agent.addListener('updateHookSettings', onSettingsUpdated);
+ }
agent.addListener('shutdown', () => {
+ if (onSettingsUpdated != null) {
+ agent.removeListener('updateHookSettings', onSettingsUpdated);
+ }
+
// If we received 'shutdown' from `agent`, we assume the `bridge` is already shutting down,
// and that caused the 'shutdown' event on the `agent`, so we don't need to call `bridge.shutdown()` here.
hook.emit('shutdown');