Skip to content

[react devtools] Device storage support #25452

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

Merged
merged 1 commit into from
Oct 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions packages/react-devtools-core/src/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ import {initBackend} from 'react-devtools-shared/src/backend';
import {__DEBUG__} from 'react-devtools-shared/src/constants';
import setupNativeStyleEditor from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor';
import {getDefaultComponentFilters} from 'react-devtools-shared/src/utils';
import {
initializeUsingCachedSettings,
cacheConsolePatchSettings,
type DevToolsSettingsManager,
} from './cachedSettings';

import type {BackendBridge} from 'react-devtools-shared/src/bridge';
import type {ComponentFilter} from 'react-devtools-shared/src/types';
Expand All @@ -29,6 +34,7 @@ type ConnectOptions = {
retryConnectionDelay?: number,
isAppActive?: () => boolean,
websocket?: ?WebSocket,
devToolsSettingsManager: ?DevToolsSettingsManager,
...
};

Expand Down Expand Up @@ -63,6 +69,7 @@ export function connectToDevTools(options: ?ConnectOptions) {
resolveRNStyle = null,
retryConnectionDelay = 2000,
isAppActive = () => true,
devToolsSettingsManager,
} = options || {};

const protocol = useHttps ? 'wss' : 'ws';
Expand All @@ -78,6 +85,16 @@ export function connectToDevTools(options: ?ConnectOptions) {
}
}

if (devToolsSettingsManager != null) {
try {
initializeUsingCachedSettings(devToolsSettingsManager);
} catch (e) {
// If we call a method on devToolsSettingsManager that throws, or if
// is invalid data read out, don't throw and don't interrupt initialization
console.error(e);
}
}

if (!isAppActive()) {
// If the app is in background, maybe retry later.
// Don't actually attempt to connect until we're in foreground.
Expand Down Expand Up @@ -157,6 +174,15 @@ export function connectToDevTools(options: ?ConnectOptions) {
},
);

if (devToolsSettingsManager != null && bridge != null) {
bridge.addListener('updateConsolePatchSettings', consolePatchSettings =>
cacheConsolePatchSettings(
devToolsSettingsManager,
consolePatchSettings,
),
);
}

// The renderer interface doesn't read saved component filters directly,
// because they are generally stored in localStorage within the context of the extension.
// Because of this it relies on the extension to pass filters.
Expand Down
77 changes: 77 additions & 0 deletions packages/react-devtools-core/src/cachedSettings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
*/

import {
type ConsolePatchSettings,
writeConsolePatchSettingsToWindow,
} from 'react-devtools-shared/src/backend/console';
import {castBool, castBrowserTheme} from 'react-devtools-shared/src/utils';

// Note: all keys should be optional in this type, because users can use newer
// versions of React DevTools with older versions of React Native, and the object
// provided by React Native may not include all of this type's fields.
export type DevToolsSettingsManager = {
getConsolePatchSettings: ?() => string,
setConsolePatchSettings: ?(key: string) => void,
};

export function initializeUsingCachedSettings(
devToolsSettingsManager: DevToolsSettingsManager,
) {
initializeConsolePatchSettings(devToolsSettingsManager);
}

function initializeConsolePatchSettings(
devToolsSettingsManager: DevToolsSettingsManager,
) {
if (devToolsSettingsManager.getConsolePatchSettings == null) {
return;
}
const consolePatchSettingsString = devToolsSettingsManager.getConsolePatchSettings();
if (consolePatchSettingsString == null) {
return;
}
const parsedConsolePatchSettings = parseConsolePatchSettings(
consolePatchSettingsString,
);
if (parsedConsolePatchSettings == null) {
return;
}
writeConsolePatchSettingsToWindow(parsedConsolePatchSettings);
}

function parseConsolePatchSettings(
consolePatchSettingsString: string,
): ?ConsolePatchSettings {
const parsedValue = JSON.parse(consolePatchSettingsString ?? '{}');
const {
appendComponentStack,
breakOnConsoleErrors,
showInlineWarningsAndErrors,
hideConsoleLogsInStrictMode,
browserTheme,
} = parsedValue;
return {
appendComponentStack: castBool(appendComponentStack) ?? true,
breakOnConsoleErrors: castBool(breakOnConsoleErrors) ?? false,
showInlineWarningsAndErrors: castBool(showInlineWarningsAndErrors) ?? true,
hideConsoleLogsInStrictMode: castBool(hideConsoleLogsInStrictMode) ?? false,
browserTheme: castBrowserTheme(browserTheme) ?? 'dark',
};
}

export function cacheConsolePatchSettings(
devToolsSettingsManager: DevToolsSettingsManager,
value: ConsolePatchSettings,
): void {
if (devToolsSettingsManager.setConsolePatchSettings == null) {
return;
}
devToolsSettingsManager.setConsolePatchSettings(JSON.stringify(value));
}
10 changes: 5 additions & 5 deletions packages/react-devtools-shared/src/backend/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
initialize as setupTraceUpdates,
toggleEnabled as setTraceUpdatesEnabled,
} from './views/TraceUpdates';
import {patch as patchConsole} from './console';
import {patch as patchConsole, type ConsolePatchSettings} from './console';
import {currentBridgeProtocol} from 'react-devtools-shared/src/bridge';

import type {BackendBridge} from 'react-devtools-shared/src/bridge';
Expand Down Expand Up @@ -712,11 +712,11 @@ export default class Agent extends EventEmitter<{
showInlineWarningsAndErrors,
hideConsoleLogsInStrictMode,
browserTheme,
}) => {
// If the frontend preference has change,
// or in the case of React Native- if the backend is just finding out the preference-
}: ConsolePatchSettings) => {
// If the frontend preferences have changed,
// or in the case of React Native- if the backend is just finding out the preferences-
// then reinstall the console overrides.
// It's safe to call these methods multiple times, so we don't need to worry about that.
// It's safe to call `patchConsole` multiple times.
patchConsole({
appendComponentStack,
breakOnConsoleErrors,
Expand Down
42 changes: 25 additions & 17 deletions packages/react-devtools-shared/src/backend/console.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {format, formatWithStyles} from './utils';
import {getInternalReactConstants} from './renderer';
import {getStackByFiberInDevAndProd} from './DevToolsFiberComponentStack';
import {consoleManagedByDevToolsDuringStrictMode} from 'react-devtools-feature-flags';
import {castBool, castBrowserTheme} from '../utils';

const OVERRIDE_CONSOLE_METHODS = ['error', 'trace', 'warn'];
const DIMMED_NODE_CONSOLE_COLOR = '\x1b[2m%s\x1b[0m';
Expand Down Expand Up @@ -143,6 +144,14 @@ const consoleSettingsRef = {
browserTheme: 'dark',
};

export type ConsolePatchSettings = {
appendComponentStack: boolean,
breakOnConsoleErrors: boolean,
showInlineWarningsAndErrors: boolean,
hideConsoleLogsInStrictMode: boolean,
browserTheme: BrowserTheme,
};

// Patches console methods to append component stack for the current fiber.
// Call unpatch() to remove the injected behavior.
export function patch({
Expand All @@ -151,13 +160,7 @@ export function patch({
showInlineWarningsAndErrors,
hideConsoleLogsInStrictMode,
browserTheme,
}: {
appendComponentStack: boolean,
breakOnConsoleErrors: boolean,
showInlineWarningsAndErrors: boolean,
hideConsoleLogsInStrictMode: boolean,
browserTheme: BrowserTheme,
}): void {
}: ConsolePatchSettings): void {
// Settings may change after we've patched the console.
// Using a shared ref allows the patch function to read the latest values.
consoleSettingsRef.appendComponentStack = appendComponentStack;
Expand Down Expand Up @@ -390,14 +393,19 @@ export function patchConsoleUsingWindowValues() {
});
}

function castBool(v: any): ?boolean {
if (v === true || v === false) {
return v;
}
}

function castBrowserTheme(v: any): ?BrowserTheme {
if (v === 'light' || v === 'dark' || v === 'auto') {
return v;
}
// After receiving cached console patch settings from React Native, we set them on window.
// When the console is initially patched (in renderer.js and hook.js), these values are read.
// The browser extension (etc.) sets these values on window, but through another method.
export function writeConsolePatchSettingsToWindow(
settings: ConsolePatchSettings,
): void {
window.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ =
settings.appendComponentStack;
window.__REACT_DEVTOOLS_BREAK_ON_CONSOLE_ERRORS__ =
settings.breakOnConsoleErrors;
window.__REACT_DEVTOOLS_SHOW_INLINE_WARNINGS_AND_ERRORS__ =
settings.showInlineWarningsAndErrors;
window.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ =
settings.hideConsoleLogsInStrictMode;
window.__REACT_DEVTOOLS_BROWSER_THEME__ = settings.browserTheme;
}
12 changes: 2 additions & 10 deletions packages/react-devtools-shared/src/bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type {
RendererID,
} from 'react-devtools-shared/src/backend/types';
import type {StyleAndLayout as StyleAndLayoutPayload} from 'react-devtools-shared/src/backend/NativeStyleEditor/types';
import type {BrowserTheme} from 'react-devtools-shared/src/devtools/views/DevTools';
import type {ConsolePatchSettings} from 'react-devtools-shared/src/backend/console';

const BATCH_DURATION = 100;

Expand Down Expand Up @@ -171,14 +171,6 @@ type NativeStyleEditor_SetValueParams = {
value: string,
};

type UpdateConsolePatchSettingsParams = {
appendComponentStack: boolean,
breakOnConsoleErrors: boolean,
showInlineWarningsAndErrors: boolean,
hideConsoleLogsInStrictMode: boolean,
browserTheme: BrowserTheme,
};

type SavedPreferencesParams = {
appendComponentStack: boolean,
breakOnConsoleErrors: boolean,
Expand Down Expand Up @@ -247,7 +239,7 @@ type FrontendEvents = {
stopProfiling: [],
storeAsGlobal: [StoreAsGlobalParams],
updateComponentFilters: [Array<ComponentFilter>],
updateConsolePatchSettings: [UpdateConsolePatchSettingsParams],
updateConsolePatchSettings: [ConsolePatchSettings],
viewAttributeSource: [ViewAttributeSourceParams],
viewElementSource: [ElementAndRendererID],

Expand Down
13 changes: 13 additions & 0 deletions packages/react-devtools-shared/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import isArray from './isArray';

import type {ComponentFilter, ElementType} from './types';
import type {LRUCache} from 'react-devtools-shared/src/types';
import type {BrowserTheme} from 'react-devtools-shared/src/devtools/views/DevTools';

// $FlowFixMe[method-unbinding]
const hasOwnProperty = Object.prototype.hasOwnProperty;
Expand Down Expand Up @@ -353,6 +354,18 @@ function parseBool(s: ?string): ?boolean {
}
}

export function castBool(v: any): ?boolean {
if (v === true || v === false) {
return v;
}
}

export function castBrowserTheme(v: any): ?BrowserTheme {
if (v === 'light' || v === 'dark' || v === 'auto') {
return v;
}
}

export function getAppendComponentStack(): boolean {
const raw = localStorageGetItem(
LOCAL_STORAGE_SHOULD_APPEND_COMPONENT_STACK_KEY,
Expand Down