Skip to content

Commit a939bd6

Browse files
committed
feat[react-devtools/extension]: use chrome.storage to persist settings across sessions
1 parent 59b4efa commit a939bd6

File tree

12 files changed

+97
-51
lines changed

12 files changed

+97
-51
lines changed

packages/react-devtools-extensions/chrome/manifest.json

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
},
4343
"permissions": [
4444
"scripting",
45+
"storage",
4546
"tabs"
4647
],
4748
"host_permissions": [

packages/react-devtools-extensions/edge/manifest.json

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
},
4343
"permissions": [
4444
"scripting",
45+
"storage",
4546
"tabs"
4647
],
4748
"host_permissions": [

packages/react-devtools-extensions/firefox/manifest.json

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
},
5050
"permissions": [
5151
"scripting",
52+
"storage",
5253
"tabs"
5354
],
5455
"host_permissions": [

packages/react-devtools-extensions/src/background/dynamicallyInjectContentScripts.js

+7
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ const contentScriptsToInject = [
2525
runAt: 'document_start',
2626
world: chrome.scripting.ExecutionWorld.MAIN,
2727
},
28+
{
29+
id: '@react-devtools/hook-settings-injector',
30+
js: ['build/hookSettingsInjector.js'],
31+
matches: ['<all_urls>'],
32+
persistAcrossSessions: true,
33+
runAt: 'document_start',
34+
},
2835
];
2936

3037
async function dynamicallyInjectContentScripts() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* global chrome */
2+
3+
// We can't use chrome.storage domain from scripts which are injected in ExecutionWorld.MAIN
4+
// This is the only purpose of this script - to send persisted settings to installHook.js content script
5+
6+
async function messageListener(event: MessageEvent) {
7+
if (event.source !== window) {
8+
return;
9+
}
10+
11+
if (event.data.source === 'react-devtools-hook-installer') {
12+
if (event.data.payload.handshake) {
13+
const settings = await chrome.storage.local.get();
14+
// If storage was empty (first installation), define default settings
15+
if (typeof settings.appendComponentStack !== 'boolean') {
16+
settings.appendComponentStack = true;
17+
}
18+
if (typeof settings.breakOnConsoleErrors !== 'boolean') {
19+
settings.breakOnConsoleErrors = false;
20+
}
21+
if (typeof settings.showInlineWarningsAndErrors !== 'boolean') {
22+
settings.showInlineWarningsAndErrors = true;
23+
}
24+
if (typeof settings.hideConsoleLogsInStrictMode !== 'boolean') {
25+
settings.hideConsoleLogsInStrictMode = false;
26+
}
27+
28+
window.postMessage({
29+
source: 'react-devtools-hook-settings-injector',
30+
payload: {settings},
31+
});
32+
33+
window.removeEventListener('message', messageListener);
34+
}
35+
}
36+
}
37+
38+
window.addEventListener('message', messageListener);
39+
window.postMessage({
40+
source: 'react-devtools-hook-settings-injector',
41+
payload: {handshake: true},
42+
});

packages/react-devtools-extensions/src/contentScripts/installHook.js

+36-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,43 @@
11
import {installHook} from 'react-devtools-shared/src/hook';
22

3-
// avoid double execution
3+
let resolveHookSettingsInjection;
4+
5+
function messageListener(event: MessageEvent) {
6+
if (event.source !== window) {
7+
return;
8+
}
9+
10+
if (event.data.source === 'react-devtools-hook-settings-injector') {
11+
// In case handshake message was sent prior to hookSettingsInjector execution
12+
// We can't guarantee order
13+
if (event.data.payload.handshake) {
14+
window.postMessage({
15+
source: 'react-devtools-hook-installer',
16+
payload: {handshake: true},
17+
});
18+
} else if (event.data.payload.settings) {
19+
window.removeEventListener('message', messageListener);
20+
resolveHookSettingsInjection(event.data.payload.settings);
21+
}
22+
}
23+
}
24+
25+
// Avoid double execution
426
if (!window.hasOwnProperty('__REACT_DEVTOOLS_GLOBAL_HOOK__')) {
5-
installHook(window);
27+
const hookSettingsPromise = new Promise(resolve => {
28+
resolveHookSettingsInjection = resolve;
29+
});
30+
31+
window.addEventListener('message', messageListener);
32+
window.postMessage({
33+
source: 'react-devtools-hook-installer',
34+
payload: {handshake: true},
35+
});
36+
37+
// Can't delay hook installation, inject settings lazily
38+
installHook(window, hookSettingsPromise);
639

7-
// detect react
40+
// Detect React
841
window.__REACT_DEVTOOLS_GLOBAL_HOOK__.on(
942
'renderer',
1043
function ({reactBuildType}) {

packages/react-devtools-extensions/src/main/index.js

+4-6
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import {startReactPolling} from './reactPolling';
2727
import cloneStyleTags from './cloneStyleTags';
2828
import fetchFileWithCaching from './fetchFileWithCaching';
2929
import injectBackendManager from './injectBackendManager';
30-
import syncSavedPreferences from './syncSavedPreferences';
3130
import registerEventsLogger from './registerEventsLogger';
3231
import getProfilingFlags from './getProfilingFlags';
3332
import debounce from './debounce';
@@ -103,6 +102,10 @@ function createBridgeAndStore() {
103102
supportsClickToInspect: true,
104103
});
105104

105+
store.addListener('updateConsolePatchSettings', settings => {
106+
chrome.storage.local.set(settings);
107+
});
108+
106109
if (!isProfiling) {
107110
// We previously stored this in performCleanup function
108111
store.profilerStore.profilingData = profilingData;
@@ -393,10 +396,6 @@ let root = null;
393396

394397
let port = null;
395398

396-
// Re-initialize saved filters on navigation,
397-
// since global values stored on window get reset in this case.
398-
chrome.devtools.network.onNavigated.addListener(syncSavedPreferences);
399-
400399
// In case when multiple navigation events emitted in a short period of time
401400
// This debounced callback primarily used to avoid mounting React DevTools multiple times, which results
402401
// into subscribing to the same events from Bridge and window multiple times
@@ -426,5 +425,4 @@ if (__IS_FIREFOX__) {
426425

427426
connectExtensionPort();
428427

429-
syncSavedPreferences();
430428
mountReactDevToolsWhenReactHasLoaded();

packages/react-devtools-extensions/src/main/syncSavedPreferences.js

-34
This file was deleted.

packages/react-devtools-extensions/webpack.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ module.exports = {
5656
proxy: './src/contentScripts/proxy.js',
5757
prepareInjection: './src/contentScripts/prepareInjection.js',
5858
installHook: './src/contentScripts/installHook.js',
59+
hookSettingsInjector: './src/contentScripts/hookSettingsInjector.js',
5960
},
6061
output: {
6162
path: __dirname + '/build',

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

+2-7
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ export default class Agent extends EventEmitter<{
149149
drawTraceUpdates: [Array<HostInstance>],
150150
disableTraceUpdates: [],
151151
getIfHasUnsupportedRendererVersion: [],
152-
updateHookSettings: [DevToolsHookSettings],
152+
updateHookSettings: [$ReadOnly<DevToolsHookSettings>]],
153153
getHookSettings: [],
154154
}> {
155155
_bridge: BackendBridge;
@@ -806,12 +806,7 @@ export default class Agent extends EventEmitter<{
806806
updateHookSettings: (settings: $ReadOnly<DevToolsHookSettings>) => void =
807807
settings => {
808808
// Propagate the settings, so Backend can subscribe to it and modify hook
809-
this.emit('updateHookSettings', {
810-
appendComponentStack: settings.appendComponentStack,
811-
breakOnConsoleErrors: settings.breakOnConsoleErrors,
812-
showInlineWarningsAndErrors: settings.showInlineWarningsAndErrors,
813-
hideConsoleLogsInStrictMode: settings.hideConsoleLogsInStrictMode,
814-
});
809+
this.emit('updateHookSettings', settings);
815810
};
816811

817812
getHookSettings: () => void = () => {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ export type DevToolsHook = {
524524
// Testing
525525
dangerous_setTargetConsoleForTesting?: (fakeConsole: Object) => void,
526526

527-
settings?: DevToolsHookSettings,
527+
settings?: $ReadOnly<DevToolsHookSettings>,
528528
...
529529
};
530530

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

+1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ export default class Store extends EventEmitter<{
9696
componentFilters: [],
9797
error: [Error],
9898
hookSettings: [$ReadOnly<DevToolsHookSettings>],
99+
updateConsolePatchSettings: [$ReadOnly<DevToolsHookSettings>],
99100
mutated: [[Array<number>, Map<number, number>]],
100101
recordChangeDescriptions: [],
101102
roots: [],

0 commit comments

Comments
 (0)