Show warning in UI when duplicate installations of DevTools extension are detected (#22563)
Juan committed
Oct 15, 2021 at 11:27 UTC
930c9e7eeb4c9721e1b8dee074c2eef4d1eae5dc
6 files changed
+115
-13
packages/react-devtools-extensions/src/background.js
+12
-4
@@ -1,12 +1,19 @@
1
-/* global chrome */
1
+// @flow strict-local
2
3
'use strict';
4
5
-const ports = {};
5
+declare var chrome: any;
6
+
7
+const ports: {
8
+ [tab: string]: {|devtools: any, 'content-script': any|},
9
+} = {};
10
11
const IS_FIREFOX = navigator.userAgent.indexOf('Firefox') >= 0;
12
9
-import {EXTENSION_INSTALL_CHECK_MESSAGE} from './constants';
13
+import {
14
+ EXTENSION_INSTALL_CHECK,
15
+ SHOW_DUPLICATE_EXTENSION_WARNING,
16
+} from './constants';
17
18
chrome.runtime.onConnect.addListener(function(port) {
19
let tab = null;
@@ -120,8 +127,9 @@ chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
127
128
chrome.runtime.onMessageExternal.addListener(
129
(request, sender, sendResponse) => {
123
- if (request === EXTENSION_INSTALL_CHECK_MESSAGE) {
130
+ if (request === EXTENSION_INSTALL_CHECK) {
131
sendResponse(true);
132
+ chrome.runtime.sendMessage(SHOW_DUPLICATE_EXTENSION_WARNING);
133
}
134
},
135
);
packages/react-devtools-extensions/src/checkForDuplicateInstallations.js
+7
-7
@@ -11,13 +11,13 @@ declare var chrome: any;
11
12
import {__DEBUG__} from 'react-devtools-shared/src/constants';
13
import {
14
- EXTENSION_INSTALL_CHECK_MESSAGE,
14
+ EXTENSION_INSTALL_CHECK,
15
EXTENSION_INSTALLATION_TYPE,
16
INTERNAL_EXTENSION_ID,
17
LOCAL_EXTENSION_ID,
18
} from './constants';
19
20
-const UNRECOGNIZED_EXTENSION_WARNING =
20
+const UNRECOGNIZED_EXTENSION_ERROR =
21
'React Developer Tools: You are running an unrecognized installation of the React Developer Tools extension, which might conflict with other versions of the extension installed in your browser. ' +
22
'Please make sure you only have a single version of the extension installed or enabled. ' +
23
'If you are developing this extension locally, make sure to build the extension using the `yarn build:<browser>:local` command.';
@@ -68,9 +68,9 @@ export function checkForDuplicateInstallations(callback: boolean => void) {
68
// detect if there are other installations of DevTools present.
69
// In this case, assume there are no duplicate exensions and show a warning about
70
// potential conflicts.
71
- console.error(UNRECOGNIZED_EXTENSION_WARNING);
71
+ console.error(UNRECOGNIZED_EXTENSION_ERROR);
72
chrome.devtools.inspectedWindow.eval(
73
- `console.error("${UNRECOGNIZED_EXTENSION_WARNING}")`,
73
+ `console.error("${UNRECOGNIZED_EXTENSION_ERROR}")`,
74
);
75
callback(false);
76
break;
@@ -80,9 +80,9 @@ export function checkForDuplicateInstallations(callback: boolean => void) {
80
// are other installations of DevTools present.
81
// In this case, assume there are no duplicate exensions and show a warning about
82
// potential conflicts.
83
- console.error(UNRECOGNIZED_EXTENSION_WARNING);
83
+ console.error(UNRECOGNIZED_EXTENSION_ERROR);
84
chrome.devtools.inspectedWindow.eval(
85
- `console.error("${UNRECOGNIZED_EXTENSION_WARNING}")`,
85
+ `console.error("${UNRECOGNIZED_EXTENSION_ERROR}")`,
86
);
87
callback(false);
88
break;
@@ -105,7 +105,7 @@ function checkForInstalledExtension(extensionId: string): Promise<boolean> {
105
return new Promise(resolve => {
106
chrome.runtime.sendMessage(
107
extensionId,
108
- EXTENSION_INSTALL_CHECK_MESSAGE,
108
+ EXTENSION_INSTALL_CHECK,
109
response => {
110
if (__DEBUG__) {
111
console.log(
packages/react-devtools-extensions/src/constants.js
+3
-1
@@ -11,7 +11,9 @@ declare var chrome: any;
11
12
export const CURRENT_EXTENSION_ID = chrome.runtime.id;
13
14
-export const EXTENSION_INSTALL_CHECK_MESSAGE = 'extension-install-check';
14
+export const EXTENSION_INSTALL_CHECK = 'extension-install-check';
15
+export const SHOW_DUPLICATE_EXTENSION_WARNING =
16
+ 'show-duplicate-extension-warning';
17
18
export const CHROME_WEBSTORE_EXTENSION_ID = 'fmkadmapgofadopljbjfkapdkoienihi';
19
export const INTERNAL_EXTENSION_ID = 'dnjnjgbfilfphmojnmhliehogmojhclc';
packages/react-devtools-extensions/src/main.js
+34
-1
@@ -22,7 +22,11 @@ import {
22
import DevTools from 'react-devtools-shared/src/devtools/views/DevTools';
23
import {__DEBUG__} from 'react-devtools-shared/src/constants';
24
import {logEvent} from 'react-devtools-shared/src/Logger';
25
-import {CURRENT_EXTENSION_ID, EXTENSION_INSTALLATION_TYPE} from './constants';
25
+import {
26
+ CURRENT_EXTENSION_ID,
27
+ EXTENSION_INSTALLATION_TYPE,
28
+ SHOW_DUPLICATE_EXTENSION_WARNING,
29
+} from './constants';
30
import {checkForDuplicateInstallations} from './checkForDuplicateInstallations';
31
32
const LOCAL_STORAGE_SUPPORTS_PROFILING_KEY =
@@ -108,11 +112,39 @@ function createPanelIfReactLoaded() {
112
let mostRecentOverrideTab = null;
113
let render = null;
114
let root = null;
115
+ let warnIfDuplicateInstallation = false;
116
117
const tabId = chrome.devtools.inspectedWindow.tabId;
118
119
registerDevToolsEventLogger('extension');
120
121
+ function onDuplicateExtensionMessage(message) {
122
+ if (message === SHOW_DUPLICATE_EXTENSION_WARNING) {
123
+ chrome.runtime.onMessage.removeListener(
124
+ onDuplicateExtensionMessage,
125
+ );
126
+
127
+ if (warnIfDuplicateInstallation === true) {
128
+ return;
129
+ }
130
+ warnIfDuplicateInstallation = true;
131
+ const errorMessage =
132
+ 'React Developer Tools: We detected that there are multiple versions of React Developer Tools ' +
133
+ 'installed and enabled in your browser at the same time, which will cause ' +
134
+ 'issues while using the extension. ' +
135
+ 'Please ensure that you have installed and enabled only a single ' +
136
+ 'version of React Developer Tools before proceeding.';
137
+ console.error(errorMessage);
138
+ chrome.devtools.inspectedWindow.eval(
139
+ `console.error("${errorMessage}")`,
140
+ );
141
+ if (render != null) {
142
+ render();
143
+ }
144
+ }
145
+ }
146
+ chrome.runtime.onMessage.addListener(onDuplicateExtensionMessage);
147
+
148
function initBridgeAndStore() {
149
const port = chrome.runtime.connect({
150
name: String(tabId),
@@ -374,6 +406,7 @@ function createPanelIfReactLoaded() {
406
hookNamesModuleLoaderFunction,
407
overrideTab,
408
profilerPortalContainer,
409
+ warnIfDuplicateInstallation,
410
showTabBar: false,
411
store,
412
warnIfUnsupportedVersionDetected: true,
packages/react-devtools-shared/src/devtools/views/DevTools.js
+4
@@ -34,6 +34,7 @@ import {SchedulingProfilerContextController} from 'react-devtools-scheduling-pro
34
import {ModalDialogContextController} from './ModalDialog';
35
import ReactLogo from './ReactLogo';
36
import UnsupportedBridgeProtocolDialog from './UnsupportedBridgeProtocolDialog';
37
+import DuplicateInstallationDialog from './DuplicateInstallationDialog';
38
import UnsupportedVersionDialog from './UnsupportedVersionDialog';
39
import WarnIfLegacyBackendDetected from './WarnIfLegacyBackendDetected';
40
import {useLocalStorage} from './hooks';
@@ -73,6 +74,7 @@ export type Props = {|
74
enabledInspectedElementContextMenu?: boolean,
75
showTabBar?: boolean,
76
store: Store,
77
+ warnIfDuplicateInstallation?: boolean,
78
warnIfLegacyBackendDetected?: boolean,
79
warnIfUnsupportedVersionDetected?: boolean,
80
viewAttributeSourceFunction?: ?ViewAttributeSource,
@@ -132,6 +134,7 @@ export default function DevTools({
134
profilerPortalContainer,
135
showTabBar = false,
136
store,
137
+ warnIfDuplicateInstallation = false,
138
warnIfLegacyBackendDetected = false,
139
warnIfUnsupportedVersionDetected = false,
140
viewAttributeSourceFunction,
@@ -319,6 +322,7 @@ export default function DevTools({
322
</ViewElementSourceContext.Provider>
323
</SettingsContextController>
324
<UnsupportedBridgeProtocolDialog />
325
+ {warnIfDuplicateInstallation && <DuplicateInstallationDialog />}
326
{warnIfLegacyBackendDetected && <WarnIfLegacyBackendDetected />}
327
{warnIfUnsupportedVersionDetected && <UnsupportedVersionDialog />}
328
</ModalDialogContextController>
packages/react-devtools-shared/src/devtools/views/DuplicateInstallationDialog.js
new
+55
@@ -0,0 +1,55 @@
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 strict-local
8
+ */
9
+
10
+import * as React from 'react';
11
+import {Fragment, useContext, useEffect} from 'react';
12
+import {isInternalFacebookBuild} from 'react-devtools-feature-flags';
13
+import {ModalDialogContext} from './ModalDialog';
14
+
15
+export default function DuplicateInstallationDialog(_: {||}) {
16
+ const {dispatch} = useContext(ModalDialogContext);
17
+
18
+ useEffect(() => {
19
+ dispatch({
20
+ canBeDismissed: false,
21
+ id: 'DuplicateInstallationDialog',
22
+ type: 'SHOW',
23
+ title: 'Duplicate Installations of DevTools Detected',
24
+ content: <DialogContent />,
25
+ });
26
+ }, []);
27
+ return null;
28
+}
29
+
30
+function DialogContent(_: {||}) {
31
+ return (
32
+ <Fragment>
33
+ <p>
34
+ We detected that there are multiple versions of React Developer Tools
35
+ installed and enabled in your browser at the same time, which will cause
36
+ issues while using the extension.
37
+ </p>
38
+ {isInternalFacebookBuild ? (
39
+ <p>
40
+ Before proceeding, please ensure that the only enabled version of
41
+ React Developer Tools is the internal (Chef-installed) version. To
42
+ manage your extensions, visit the <code>about://extensions</code> page
43
+ in your browser.
44
+ </p>
45
+ ) : (
46
+ <p>
47
+ Please ensure that you have installed and enabled only a single
48
+ version of React Developer Tools before proceeding. To manage your
49
+ extensions, visit the <code>about://extensions</code> page in your
50
+ browser.
51
+ </p>
52
+ )}
53
+ </Fragment>
54
+ );
55
+}