Skip to content

Commit

Permalink
feat[react-devtools/extension]: use chrome.storage to persist setting…
Browse files Browse the repository at this point in the history
…s across sessions
  • Loading branch information
hoxyq committed Sep 18, 2024
1 parent e33acfd commit 1396e93
Show file tree
Hide file tree
Showing 12 changed files with 99 additions and 51 deletions.
1 change: 1 addition & 0 deletions packages/react-devtools-extensions/chrome/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
},
"permissions": [
"scripting",
"storage",
"tabs"
],
"host_permissions": [
Expand Down
1 change: 1 addition & 0 deletions packages/react-devtools-extensions/edge/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
},
"permissions": [
"scripting",
"storage",
"tabs"
],
"host_permissions": [
Expand Down
1 change: 1 addition & 0 deletions packages/react-devtools-extensions/firefox/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
},
"permissions": [
"scripting",
"storage",
"tabs"
],
"host_permissions": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ const contentScriptsToInject = [
runAt: 'document_start',
world: chrome.scripting.ExecutionWorld.MAIN,
},
{
id: '@react-devtools/hook-settings-injector',
js: ['build/hookSettingsInjector.js'],
matches: ['<all_urls>'],
persistAcrossSessions: true,
runAt: 'document_start',
},
];

async function dynamicallyInjectContentScripts() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/* global chrome */

// We can't use chrome.storage domain from scripts which are injected in ExecutionWorld.MAIN
// This is the only purpose of this script - to send persisted settings to installHook.js content script

async function messageListener(event: MessageEvent) {
if (event.source !== window) {
return;
}

if (event.data.source === 'react-devtools-hook-installer') {
if (event.data.payload.handshake) {
const settings = await chrome.storage.local.get();
// If storage was empty (first installation), define default settings
if (typeof settings.appendComponentStack !== 'boolean') {
settings.appendComponentStack = true;
}
if (typeof settings.breakOnConsoleErrors !== 'boolean') {
settings.breakOnConsoleErrors = false;
}
if (typeof settings.showInlineWarningsAndErrors !== 'boolean') {
settings.showInlineWarningsAndErrors = true;
}
if (typeof settings.hideConsoleLogsInStrictMode !== 'boolean') {
settings.hideConsoleLogsInStrictMode = false;
}

window.postMessage({
source: 'react-devtools-hook-settings-injector',
payload: {settings},
});

window.removeEventListener('message', messageListener);
}
}
}

window.addEventListener('message', messageListener);
window.postMessage({
source: 'react-devtools-hook-settings-injector',
payload: {handshake: true},
});
Original file line number Diff line number Diff line change
@@ -1,10 +1,43 @@
import {installHook} from 'react-devtools-shared/src/hook';

// avoid double execution
let resolveHookSettingsInjection;

function messageListener(event: MessageEvent) {
if (event.source !== window) {
return;
}

if (event.data.source === 'react-devtools-hook-settings-injector') {
// In case handshake message was sent prior to hookSettingsInjector execution
// We can't guarantee order
if (event.data.payload.handshake) {
window.postMessage({
source: 'react-devtools-hook-installer',
payload: {handshake: true},
});
} else if (event.data.payload.settings) {
window.removeEventListener('message', messageListener);
resolveHookSettingsInjection(event.data.payload.settings);
}
}
}

// Avoid double execution
if (!window.hasOwnProperty('__REACT_DEVTOOLS_GLOBAL_HOOK__')) {
installHook(window);
const hookSettingsPromise = new Promise(resolve => {
resolveHookSettingsInjection = resolve;
});

window.addEventListener('message', messageListener);
window.postMessage({
source: 'react-devtools-hook-installer',
payload: {handshake: true},
});

// Can't delay hook installation, inject settings lazily
installHook(window, hookSettingsPromise);

// detect react
// Detect React
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.on(
'renderer',
function ({reactBuildType}) {
Expand Down
10 changes: 4 additions & 6 deletions packages/react-devtools-extensions/src/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import {startReactPolling} from './reactPolling';
import cloneStyleTags from './cloneStyleTags';
import fetchFileWithCaching from './fetchFileWithCaching';
import injectBackendManager from './injectBackendManager';
import syncSavedPreferences from './syncSavedPreferences';
import registerEventsLogger from './registerEventsLogger';
import getProfilingFlags from './getProfilingFlags';
import debounce from './debounce';
Expand Down Expand Up @@ -103,6 +102,10 @@ function createBridgeAndStore() {
supportsClickToInspect: true,
});

store.addListener('settingsUpdated', settings => {
chrome.storage.local.set(settings);
});

if (!isProfiling) {
// We previously stored this in performCleanup function
store.profilerStore.profilingData = profilingData;
Expand Down Expand Up @@ -393,10 +396,6 @@ let root = null;

let port = null;

// Re-initialize saved filters on navigation,
// since global values stored on window get reset in this case.
chrome.devtools.network.onNavigated.addListener(syncSavedPreferences);

// In case when multiple navigation events emitted in a short period of time
// This debounced callback primarily used to avoid mounting React DevTools multiple times, which results
// into subscribing to the same events from Bridge and window multiple times
Expand Down Expand Up @@ -426,5 +425,4 @@ if (__IS_FIREFOX__) {

connectExtensionPort();

syncSavedPreferences();
mountReactDevToolsWhenReactHasLoaded();

This file was deleted.

1 change: 1 addition & 0 deletions packages/react-devtools-extensions/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ module.exports = {
proxy: './src/contentScripts/proxy.js',
prepareInjection: './src/contentScripts/prepareInjection.js',
installHook: './src/contentScripts/installHook.js',
hookSettingsInjector: './src/contentScripts/hookSettingsInjector.js',
},
output: {
path: __dirname + '/build',
Expand Down
9 changes: 2 additions & 7 deletions packages/react-devtools-shared/src/backend/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ export default class Agent extends EventEmitter<{
drawTraceUpdates: [Array<HostInstance>],
disableTraceUpdates: [],
getIfHasUnsupportedRendererVersion: [],
updateHookSettings: [DevToolsHookSettings],
updateHookSettings: [$ReadOnly<DevToolsHookSettings>],
getHookSettings: [],
}> {
_bridge: BackendBridge;
Expand Down Expand Up @@ -806,12 +806,7 @@ export default class Agent extends EventEmitter<{
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,
});
this.emit('updateHookSettings', settings);
};

getHookSettings: () => void = () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/react-devtools-shared/src/backend/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ export type DevToolsHook = {
// Testing
dangerous_setTargetConsoleForTesting?: (fakeConsole: Object) => void,

settings?: DevToolsHookSettings,
settings?: $ReadOnly<DevToolsHookSettings>,
...
};

Expand Down
3 changes: 3 additions & 0 deletions packages/react-devtools-shared/src/devtools/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export default class Store extends EventEmitter<{
componentFilters: [],
error: [Error],
hookSettings: [$ReadOnly<DevToolsHookSettings>],
settingsUpdated: [$ReadOnly<DevToolsHookSettings>],
mutated: [[Array<number>, Map<number, number>]],
recordChangeDescriptions: [],
roots: [],
Expand Down Expand Up @@ -1519,7 +1520,9 @@ export default class Store extends EventEmitter<{
updateHookSettings: (settings: $ReadOnly<DevToolsHookSettings>) => void =
settings => {
this._hookSettings = settings;

this._bridge.send('updateHookSettings', settings);
this.emit('settingsUpdated', settings);
};

onHookSettings: (settings: $ReadOnly<DevToolsHookSettings>) => void =
Expand Down

0 comments on commit 1396e93

Please sign in to comment.