Skip to content

Commit b66ca95

Browse files
committed
[react devtools] device storage
1 parent 66a8ed0 commit b66ca95

File tree

6 files changed

+148
-32
lines changed

6 files changed

+148
-32
lines changed

packages/react-devtools-core/src/backend.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ import {initBackend} from 'react-devtools-shared/src/backend';
1414
import {__DEBUG__} from 'react-devtools-shared/src/constants';
1515
import setupNativeStyleEditor from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor';
1616
import {getDefaultComponentFilters} from 'react-devtools-shared/src/utils';
17+
import {
18+
initializeUsingCachedSettings,
19+
cacheSettings,
20+
type CachedSettingsStore,
21+
} from './cachedSettings';
1722

1823
import type {BackendBridge} from 'react-devtools-shared/src/bridge';
1924
import type {ComponentFilter} from 'react-devtools-shared/src/types';
@@ -29,6 +34,7 @@ type ConnectOptions = {
2934
retryConnectionDelay?: number,
3035
isAppActive?: () => boolean,
3136
websocket?: ?WebSocket,
37+
cachedSettingsStore: ?CachedSettingsStore,
3238
...
3339
};
3440

@@ -63,6 +69,7 @@ export function connectToDevTools(options: ?ConnectOptions) {
6369
resolveRNStyle = null,
6470
retryConnectionDelay = 2000,
6571
isAppActive = () => true,
72+
cachedSettingsStore,
6673
} = options || {};
6774

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

88+
if (cachedSettingsStore != null) {
89+
try {
90+
initializeUsingCachedSettings(cachedSettingsStore);
91+
} catch (e) {
92+
// If we're passed a cachedSettingsStore.getValue that throws, or there
93+
// is invalid data read out, don't throw and don't interrupt initialization
94+
console.error(e);
95+
}
96+
}
97+
8198
if (!isAppActive()) {
8299
// If the app is in background, maybe retry later.
83100
// Don't actually attempt to connect until we're in foreground.
@@ -157,6 +174,12 @@ export function connectToDevTools(options: ?ConnectOptions) {
157174
},
158175
);
159176

177+
if (cachedSettingsStore != null) {
178+
bridge.addListener('updateConsolePatchSettings', consolePatchSettings =>
179+
cacheSettings(cachedSettingsStore, {consolePatchSettings}),
180+
);
181+
}
182+
160183
// The renderer interface doesn't read saved component filters directly,
161184
// because they are generally stored in localStorage within the context of the extension.
162185
// Because of this it relies on the extension to pass filters.
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
*/
9+
10+
import {
11+
type ConsolePatchSettings,
12+
writeConsolePatchSettingsToWindow,
13+
} from 'react-devtools-shared/src/backend/console';
14+
import {castBool, castBrowserTheme} from 'react-devtools-shared/src/utils';
15+
16+
export type CachedSettingsStore = {
17+
setValue: (key: string, value: string) => void,
18+
getValue: (key: string) => ?string,
19+
};
20+
21+
export type CachedSettings = {
22+
consolePatchSettings: ?ConsolePatchSettings,
23+
};
24+
25+
const CONSOLE_PATCH_SETTINGS_KEY = 'ConsolePatchSettings';
26+
27+
export function initializeUsingCachedSettings(
28+
cachedSettingsStore: CachedSettingsStore,
29+
) {
30+
const cachedSettingsString = cachedSettingsStore.getValue(
31+
CONSOLE_PATCH_SETTINGS_KEY,
32+
);
33+
if (cachedSettingsString == null) {
34+
return;
35+
}
36+
const cachedSettings = parseCachedSettings(cachedSettingsString);
37+
if (cachedSettings != null && cachedSettings.consolePatchSettings != null) {
38+
writeConsolePatchSettingsToWindow(cachedSettings.consolePatchSettings);
39+
}
40+
}
41+
42+
function parseCachedSettings(cachedSettingsString: string): ?CachedSettings {
43+
const parsedValue = JSON.parse(cachedSettingsString);
44+
45+
if (typeof parsedValue === 'object' && parsedValue != null) {
46+
const consolePatchSettings = parseConsolePatchSettings(
47+
parsedValue.consolePatchSettings,
48+
);
49+
return {
50+
consolePatchSettings,
51+
};
52+
}
53+
}
54+
55+
function parseConsolePatchSettings(value: any): ?ConsolePatchSettings {
56+
if (typeof value !== 'object' || value === null) {
57+
return;
58+
}
59+
const {
60+
appendComponentStack,
61+
breakOnConsoleErrors,
62+
showInlineWarningsAndErrors,
63+
hideConsoleLogsInStrictMode,
64+
browserTheme,
65+
} = value;
66+
return {
67+
appendComponentStack: castBool(appendComponentStack) ?? true,
68+
breakOnConsoleErrors: castBool(breakOnConsoleErrors) ?? false,
69+
showInlineWarningsAndErrors: castBool(showInlineWarningsAndErrors) ?? true,
70+
hideConsoleLogsInStrictMode: castBool(hideConsoleLogsInStrictMode) ?? false,
71+
browserTheme: castBrowserTheme(browserTheme) ?? 'dark',
72+
};
73+
}
74+
75+
export function cacheSettings(
76+
cachedSettings: CachedSettingsStore,
77+
value: CachedSettings,
78+
): void {
79+
cachedSettings.setValue(CONSOLE_PATCH_SETTINGS_KEY, JSON.stringify(value));
80+
}

packages/react-devtools-shared/src/backend/agent.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
initialize as setupTraceUpdates,
2626
toggleEnabled as setTraceUpdatesEnabled,
2727
} from './views/TraceUpdates';
28-
import {patch as patchConsole} from './console';
28+
import {patch as patchConsole, type ConsolePatchSettings} from './console';
2929
import {currentBridgeProtocol} from 'react-devtools-shared/src/bridge';
3030

3131
import type {BackendBridge} from 'react-devtools-shared/src/bridge';
@@ -712,11 +712,11 @@ export default class Agent extends EventEmitter<{
712712
showInlineWarningsAndErrors,
713713
hideConsoleLogsInStrictMode,
714714
browserTheme,
715-
}) => {
716-
// If the frontend preference has change,
717-
// or in the case of React Native- if the backend is just finding out the preference-
715+
}: ConsolePatchSettings) => {
716+
// If the frontend preferences have changed,
717+
// or in the case of React Native- if the backend is just finding out the preferences-
718718
// then reinstall the console overrides.
719-
// It's safe to call these methods multiple times, so we don't need to worry about that.
719+
// It's safe to call `patchConsole` multiple times.
720720
patchConsole({
721721
appendComponentStack,
722722
breakOnConsoleErrors,

packages/react-devtools-shared/src/backend/console.js

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {format, formatWithStyles} from './utils';
1515
import {getInternalReactConstants} from './renderer';
1616
import {getStackByFiberInDevAndProd} from './DevToolsFiberComponentStack';
1717
import {consoleManagedByDevToolsDuringStrictMode} from 'react-devtools-feature-flags';
18+
import {castBool, castBrowserTheme} from '../utils';
1819

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

147+
export type ConsolePatchSettings = {
148+
appendComponentStack: boolean,
149+
breakOnConsoleErrors: boolean,
150+
showInlineWarningsAndErrors: boolean,
151+
hideConsoleLogsInStrictMode: boolean,
152+
browserTheme: BrowserTheme,
153+
};
154+
146155
// Patches console methods to append component stack for the current fiber.
147156
// Call unpatch() to remove the injected behavior.
148157
export function patch({
@@ -151,13 +160,7 @@ export function patch({
151160
showInlineWarningsAndErrors,
152161
hideConsoleLogsInStrictMode,
153162
browserTheme,
154-
}: {
155-
appendComponentStack: boolean,
156-
breakOnConsoleErrors: boolean,
157-
showInlineWarningsAndErrors: boolean,
158-
hideConsoleLogsInStrictMode: boolean,
159-
browserTheme: BrowserTheme,
160-
}): void {
163+
}: ConsolePatchSettings): void {
161164
// Settings may change after we've patched the console.
162165
// Using a shared ref allows the patch function to read the latest values.
163166
consoleSettingsRef.appendComponentStack = appendComponentStack;
@@ -390,14 +393,19 @@ export function patchConsoleUsingWindowValues() {
390393
});
391394
}
392395

393-
function castBool(v: any): ?boolean {
394-
if (v === true || v === false) {
395-
return v;
396-
}
397-
}
398-
399-
function castBrowserTheme(v: any): ?BrowserTheme {
400-
if (v === 'light' || v === 'dark' || v === 'auto') {
401-
return v;
402-
}
396+
// After receiving cached console patch settings from React Native, we set them on window.
397+
// When the console is initially patched (in renderer.js and hook.js), these values are read.
398+
// The browser extension (etc.) sets these values on window, but through another method.
399+
export function writeConsolePatchSettingsToWindow(
400+
settings: ConsolePatchSettings,
401+
): void {
402+
window.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ =
403+
settings.appendComponentStack;
404+
window.__REACT_DEVTOOLS_BREAK_ON_CONSOLE_ERRORS__ =
405+
settings.breakOnConsoleErrors;
406+
window.__REACT_DEVTOOLS_SHOW_INLINE_WARNINGS_AND_ERRORS__ =
407+
settings.showInlineWarningsAndErrors;
408+
window.__REACT_DEVTOOLS_HIDE_CONSOLE_LOGS_IN_STRICT_MODE__ =
409+
settings.hideConsoleLogsInStrictMode;
410+
window.__REACT_DEVTOOLS_BROWSER_THEME__ = settings.browserTheme;
403411
}

packages/react-devtools-shared/src/bridge.js

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import type {
1717
RendererID,
1818
} from 'react-devtools-shared/src/backend/types';
1919
import type {StyleAndLayout as StyleAndLayoutPayload} from 'react-devtools-shared/src/backend/NativeStyleEditor/types';
20-
import type {BrowserTheme} from 'react-devtools-shared/src/devtools/views/DevTools';
20+
import type {ConsolePatchSettings} from 'react-devtools-shared/src/backend/console';
2121

2222
const BATCH_DURATION = 100;
2323

@@ -171,14 +171,6 @@ type NativeStyleEditor_SetValueParams = {
171171
value: string,
172172
};
173173

174-
type UpdateConsolePatchSettingsParams = {
175-
appendComponentStack: boolean,
176-
breakOnConsoleErrors: boolean,
177-
showInlineWarningsAndErrors: boolean,
178-
hideConsoleLogsInStrictMode: boolean,
179-
browserTheme: BrowserTheme,
180-
};
181-
182174
type SavedPreferencesParams = {
183175
appendComponentStack: boolean,
184176
breakOnConsoleErrors: boolean,
@@ -247,7 +239,7 @@ type FrontendEvents = {
247239
stopProfiling: [],
248240
storeAsGlobal: [StoreAsGlobalParams],
249241
updateComponentFilters: [Array<ComponentFilter>],
250-
updateConsolePatchSettings: [UpdateConsolePatchSettingsParams],
242+
updateConsolePatchSettings: [ConsolePatchSettings],
251243
viewAttributeSource: [ViewAttributeSourceParams],
252244
viewElementSource: [ElementAndRendererID],
253245

packages/react-devtools-shared/src/utils.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import isArray from './isArray';
5555

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

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

357+
export function castBool(v: any): ?boolean {
358+
if (v === true || v === false) {
359+
return v;
360+
}
361+
}
362+
363+
export function castBrowserTheme(v: any): ?BrowserTheme {
364+
if (v === 'light' || v === 'dark' || v === 'auto') {
365+
return v;
366+
}
367+
}
368+
356369
export function getAppendComponentStack(): boolean {
357370
const raw = localStorageGetItem(
358371
LOCAL_STORAGE_SHOULD_APPEND_COMPONENT_STACK_KEY,

0 commit comments

Comments
 (0)