Skip to content

Commit

Permalink
refactor[react-devtools]: propagate settings from global hook object …
Browse files Browse the repository at this point in the history
…to frontend (#30610)

Stacked on #30597 and whats under
it. See [this
commit](59b4efa).

With this change, the initial values for console patching settings are
propagated from hook (which is the source of truth now, because of
#30596) to the UI. Instead of
reading from `localStorage` the frontend is now requesting it from the
hook. This happens when settings modal is rendered, and wrapped in a
transition. Also, this is happening even if settings modal is not opened
yet, so we have enough time to fetch this data without displaying loader
or similar UI.
  • Loading branch information
hoxyq authored Sep 18, 2024
1 parent fce4606 commit e33acfd
Show file tree
Hide file tree
Showing 11 changed files with 145 additions and 99 deletions.
4 changes: 2 additions & 2 deletions packages/react-devtools-core/src/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export function connectToDevTools(options: ?ConnectOptions) {
);

if (devToolsSettingsManager != null && bridge != null) {
bridge.addListener('updateConsolePatchSettings', consolePatchSettings =>
bridge.addListener('updateHookSettings', consolePatchSettings =>
cacheConsolePatchSettings(
devToolsSettingsManager,
consolePatchSettings,
Expand Down Expand Up @@ -368,7 +368,7 @@ export function connectWithCustomMessagingProtocol({
);

if (settingsManager != null) {
bridge.addListener('updateConsolePatchSettings', consolePatchSettings =>
bridge.addListener('updateHookSettings', consolePatchSettings =>
cacheConsolePatchSettings(settingsManager, consolePatchSettings),
);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/react-devtools-core/src/cachedSettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function parseConsolePatchSettings(

export function cacheConsolePatchSettings(
devToolsSettingsManager: DevToolsSettingsManager,
value: ConsolePatchSettings,
value: $ReadOnly<ConsolePatchSettings>,
): void {
if (devToolsSettingsManager.setConsolePatchSettings == null) {
return;
Expand Down
37 changes: 23 additions & 14 deletions packages/react-devtools-shared/src/backend/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ export default class Agent extends EventEmitter<{
disableTraceUpdates: [],
getIfHasUnsupportedRendererVersion: [],
updateHookSettings: [DevToolsHookSettings],
getHookSettings: [],
}> {
_bridge: BackendBridge;
_isProfiling: boolean = false;
Expand Down Expand Up @@ -213,10 +214,10 @@ export default class Agent extends EventEmitter<{
this.syncSelectionFromBuiltinElementsPanel,
);
bridge.addListener('shutdown', this.shutdown);
bridge.addListener(
'updateConsolePatchSettings',
this.updateConsolePatchSettings,
);

bridge.addListener('updateHookSettings', this.updateHookSettings);
bridge.addListener('getHookSettings', this.getHookSettings);

bridge.addListener('updateComponentFilters', this.updateComponentFilters);
bridge.addListener('getEnvironmentNames', this.getEnvironmentNames);
bridge.addListener(
Expand Down Expand Up @@ -802,18 +803,26 @@ export default class Agent extends EventEmitter<{
}
};

updateConsolePatchSettings: (
settings: $ReadOnly<DevToolsHookSettings>,
) => void = settings => {
// Propagate the settings, so Backend can subscribe to it and modify hook
this.emit('updateHookSettings', {
appendComponentStack: settings.appendComponentStack,
breakOnConsoleErrors: settings.breakOnConsoleErrors,
showInlineWarningsAndErrors: settings.showInlineWarningsAndErrors,
hideConsoleLogsInStrictMode: settings.hideConsoleLogsInStrictMode,
});
updateHookSettings: (settings: $ReadOnly<DevToolsHookSettings>) => void =
settings => {
// Propagate the settings, so Backend can subscribe to it and modify hook
this.emit('updateHookSettings', {
appendComponentStack: settings.appendComponentStack,
breakOnConsoleErrors: settings.breakOnConsoleErrors,
showInlineWarningsAndErrors: settings.showInlineWarningsAndErrors,
hideConsoleLogsInStrictMode: settings.hideConsoleLogsInStrictMode,
});
};

getHookSettings: () => void = () => {
this.emit('getHookSettings');
};

onHookSettings: (settings: $ReadOnly<DevToolsHookSettings>) => void =
settings => {
this._bridge.send('hookSettings', settings);
};

updateComponentFilters: (componentFilters: Array<ComponentFilter>) => void =
componentFilters => {
for (const rendererIDString in this._rendererInterfaces) {
Expand Down
7 changes: 7 additions & 0 deletions packages/react-devtools-shared/src/backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export function initBackend(
hook.sub('fastRefreshScheduled', agent.onFastRefreshScheduled),
hook.sub('operations', agent.onHookOperations),
hook.sub('traceUpdates', agent.onTraceUpdates),
hook.sub('settingsInitialized', agent.onHookSettings),

// TODO Add additional subscriptions required for profiling mode
];
Expand Down Expand Up @@ -87,6 +88,12 @@ export function initBackend(
hook.settings = settings;
});

agent.addListener('getHookSettings', () => {
if (hook.settings != null) {
agent.onHookSettings(hook.settings);
}
});

return () => {
subs.forEach(fn => fn());
};
Expand Down
6 changes: 5 additions & 1 deletion packages/react-devtools-shared/src/bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ export type BackendEvents = {
{isSupported: boolean, validAttributes: ?$ReadOnlyArray<string>},
],
NativeStyleEditor_styleAndLayout: [StyleAndLayoutPayload],

hookSettings: [$ReadOnly<DevToolsHookSettings>],
};

type FrontendEvents = {
Expand Down Expand Up @@ -241,7 +243,7 @@ type FrontendEvents = {
storeAsGlobal: [StoreAsGlobalParams],
updateComponentFilters: [Array<ComponentFilter>],
getEnvironmentNames: [],
updateConsolePatchSettings: [DevToolsHookSettings],
updateHookSettings: [$ReadOnly<DevToolsHookSettings>],
viewAttributeSource: [ViewAttributeSourceParams],
viewElementSource: [ElementAndRendererID],

Expand All @@ -267,6 +269,8 @@ type FrontendEvents = {

resumeElementPolling: [],
pauseElementPolling: [],

getHookSettings: [],
};

class Bridge<
Expand Down
25 changes: 25 additions & 0 deletions packages/react-devtools-shared/src/devtools/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import type {
BridgeProtocol,
} from 'react-devtools-shared/src/bridge';
import UnsupportedBridgeOperationError from 'react-devtools-shared/src/UnsupportedBridgeOperationError';
import type {DevToolsHookSettings} from '../backend/types';

const debug = (methodName: string, ...args: Array<string>) => {
if (__DEBUG__) {
Expand Down Expand Up @@ -94,6 +95,7 @@ export default class Store extends EventEmitter<{
collapseNodesByDefault: [],
componentFilters: [],
error: [Error],
hookSettings: [$ReadOnly<DevToolsHookSettings>],
mutated: [[Array<number>, Map<number, number>]],
recordChangeDescriptions: [],
roots: [],
Expand Down Expand Up @@ -192,6 +194,7 @@ export default class Store extends EventEmitter<{
_weightAcrossRoots: number = 0;

_shouldCheckBridgeProtocolCompatibility: boolean = false;
_hookSettings: $ReadOnly<DevToolsHookSettings> | null = null;

constructor(bridge: FrontendBridge, config?: Config) {
super();
Expand Down Expand Up @@ -270,6 +273,7 @@ export default class Store extends EventEmitter<{

bridge.addListener('backendVersion', this.onBridgeBackendVersion);
bridge.addListener('saveToClipboard', this.onSaveToClipboard);
bridge.addListener('hookSettings', this.onHookSettings);
bridge.addListener('backendInitialized', this.onBackendInitialized);
}

Expand Down Expand Up @@ -1501,8 +1505,29 @@ export default class Store extends EventEmitter<{

this._bridge.send('getBackendVersion');
this._bridge.send('getIfHasUnsupportedRendererVersion');
this._bridge.send('getHookSettings'); // Warm up cached hook settings
};

getHookSettings: () => void = () => {
if (this._hookSettings != null) {
this.emit('hookSettings', this._hookSettings);
} else {
this._bridge.send('getHookSettings');
}
};

updateHookSettings: (settings: $ReadOnly<DevToolsHookSettings>) => void =
settings => {
this._hookSettings = settings;
this._bridge.send('updateHookSettings', settings);
};

onHookSettings: (settings: $ReadOnly<DevToolsHookSettings>) => void =
settings => {
this._hookSettings = settings;
this.emit('hookSettings', settings);
};

// The Store should never throw an Error without also emitting an event.
// Otherwise Store errors will be invisible to users,
// but the downstream errors they cause will be reported as bugs.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,49 @@
*/

import * as React from 'react';
import {useContext} from 'react';
import {SettingsContext} from './SettingsContext';
import {use, useState, useEffect} from 'react';

import type {DevToolsHookSettings} from 'react-devtools-shared/src/backend/types';
import type Store from 'react-devtools-shared/src/devtools/store';

import styles from './SettingsShared.css';

export default function DebuggingSettings(_: {}): React.Node {
const {
type Props = {
hookSettings: Promise<$ReadOnly<DevToolsHookSettings>>,
store: Store,
};

export default function DebuggingSettings({
hookSettings,
store,
}: Props): React.Node {
const usedHookSettings = use(hookSettings);

const [appendComponentStack, setAppendComponentStack] = useState(
usedHookSettings.appendComponentStack,
);
const [breakOnConsoleErrors, setBreakOnConsoleErrors] = useState(
usedHookSettings.breakOnConsoleErrors,
);
const [hideConsoleLogsInStrictMode, setHideConsoleLogsInStrictMode] =
useState(usedHookSettings.hideConsoleLogsInStrictMode);
const [showInlineWarningsAndErrors, setShowInlineWarningsAndErrors] =
useState(usedHookSettings.showInlineWarningsAndErrors);

useEffect(() => {
store.updateHookSettings({
appendComponentStack,
breakOnConsoleErrors,
showInlineWarningsAndErrors,
hideConsoleLogsInStrictMode,
});
}, [
store,
appendComponentStack,
breakOnConsoleErrors,
hideConsoleLogsInStrictMode,
setAppendComponentStack,
setBreakOnConsoleErrors,
setShowInlineWarningsAndErrors,
showInlineWarningsAndErrors,
setHideConsoleLogsInStrictMode,
} = useContext(SettingsContext);
hideConsoleLogsInStrictMode,
]);

return (
<div className={styles.Settings}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,7 @@ import {
import {
LOCAL_STORAGE_BROWSER_THEME,
LOCAL_STORAGE_PARSE_HOOK_NAMES_KEY,
LOCAL_STORAGE_SHOULD_BREAK_ON_CONSOLE_ERRORS,
LOCAL_STORAGE_SHOULD_APPEND_COMPONENT_STACK_KEY,
LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY,
LOCAL_STORAGE_SHOW_INLINE_WARNINGS_AND_ERRORS_KEY,
LOCAL_STORAGE_HIDE_CONSOLE_LOGS_IN_STRICT_MODE,
} from 'react-devtools-shared/src/constants';
import {
COMFORTABLE_LINE_HEIGHT,
Expand Down Expand Up @@ -118,30 +114,10 @@ function SettingsContextController({
LOCAL_STORAGE_BROWSER_THEME,
'auto',
);
const [appendComponentStack, setAppendComponentStack] =
useLocalStorageWithLog<boolean>(
LOCAL_STORAGE_SHOULD_APPEND_COMPONENT_STACK_KEY,
true,
);
const [breakOnConsoleErrors, setBreakOnConsoleErrors] =
useLocalStorageWithLog<boolean>(
LOCAL_STORAGE_SHOULD_BREAK_ON_CONSOLE_ERRORS,
false,
);
const [parseHookNames, setParseHookNames] = useLocalStorageWithLog<boolean>(
LOCAL_STORAGE_PARSE_HOOK_NAMES_KEY,
false,
);
const [hideConsoleLogsInStrictMode, setHideConsoleLogsInStrictMode] =
useLocalStorageWithLog<boolean>(
LOCAL_STORAGE_HIDE_CONSOLE_LOGS_IN_STRICT_MODE,
false,
);
const [showInlineWarningsAndErrors, setShowInlineWarningsAndErrors] =
useLocalStorageWithLog<boolean>(
LOCAL_STORAGE_SHOW_INLINE_WARNINGS_AND_ERRORS_KEY,
true,
);
const [traceUpdatesEnabled, setTraceUpdatesEnabled] =
useLocalStorageWithLog<boolean>(
LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY,
Expand Down Expand Up @@ -196,64 +172,33 @@ function SettingsContextController({
}
}, [browserTheme, theme, documentElements]);

useEffect(() => {
bridge.send('updateConsolePatchSettings', {
appendComponentStack,
breakOnConsoleErrors,
showInlineWarningsAndErrors,
hideConsoleLogsInStrictMode,
});
}, [
bridge,
appendComponentStack,
breakOnConsoleErrors,
showInlineWarningsAndErrors,
hideConsoleLogsInStrictMode,
]);

useEffect(() => {
bridge.send('setTraceUpdatesEnabled', traceUpdatesEnabled);
}, [bridge, traceUpdatesEnabled]);

const value = useMemo(
() => ({
appendComponentStack,
breakOnConsoleErrors,
displayDensity,
lineHeight:
displayDensity === 'compact'
? COMPACT_LINE_HEIGHT
: COMFORTABLE_LINE_HEIGHT,
parseHookNames,
setAppendComponentStack,
setBreakOnConsoleErrors,
setDisplayDensity,
setParseHookNames,
setTheme,
setTraceUpdatesEnabled,
setShowInlineWarningsAndErrors,
showInlineWarningsAndErrors,
setHideConsoleLogsInStrictMode,
hideConsoleLogsInStrictMode,
theme,
browserTheme,
traceUpdatesEnabled,
}),
[
appendComponentStack,
breakOnConsoleErrors,
displayDensity,
parseHookNames,
setAppendComponentStack,
setBreakOnConsoleErrors,
setDisplayDensity,
setParseHookNames,
setTheme,
setTraceUpdatesEnabled,
setShowInlineWarningsAndErrors,
showInlineWarningsAndErrors,
setHideConsoleLogsInStrictMode,
hideConsoleLogsInStrictMode,
theme,
browserTheme,
traceUpdatesEnabled,
Expand Down
Loading

0 comments on commit e33acfd

Please sign in to comment.