Skip to content

Commit

Permalink
Show warning in UI when duplicate installations of DevTools extension…
Browse files Browse the repository at this point in the history
… are detected (facebook#22563)
  • Loading branch information
Juan authored and zhengjitf committed Apr 15, 2022
1 parent 38c192e commit 4ceb0cb
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 13 deletions.
16 changes: 12 additions & 4 deletions packages/react-devtools-extensions/src/background.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
/* global chrome */
// @flow strict-local

'use strict';

const ports = {};
declare var chrome: any;

const ports: {
[tab: string]: {|devtools: any, 'content-script': any|},
} = {};

const IS_FIREFOX = navigator.userAgent.indexOf('Firefox') >= 0;

import {EXTENSION_INSTALL_CHECK_MESSAGE} from './constants';
import {
EXTENSION_INSTALL_CHECK,
SHOW_DUPLICATE_EXTENSION_WARNING,
} from './constants';

chrome.runtime.onConnect.addListener(function(port) {
let tab = null;
Expand Down Expand Up @@ -120,8 +127,9 @@ chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {

chrome.runtime.onMessageExternal.addListener(
(request, sender, sendResponse) => {
if (request === EXTENSION_INSTALL_CHECK_MESSAGE) {
if (request === EXTENSION_INSTALL_CHECK) {
sendResponse(true);
chrome.runtime.sendMessage(SHOW_DUPLICATE_EXTENSION_WARNING);
}
},
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ declare var chrome: any;

import {__DEBUG__} from 'react-devtools-shared/src/constants';
import {
EXTENSION_INSTALL_CHECK_MESSAGE,
EXTENSION_INSTALL_CHECK,
EXTENSION_INSTALLATION_TYPE,
INTERNAL_EXTENSION_ID,
LOCAL_EXTENSION_ID,
} from './constants';

const UNRECOGNIZED_EXTENSION_WARNING =
const UNRECOGNIZED_EXTENSION_ERROR =
'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. ' +
'Please make sure you only have a single version of the extension installed or enabled. ' +
'If you are developing this extension locally, make sure to build the extension using the `yarn build:<browser>:local` command.';
Expand Down Expand Up @@ -68,9 +68,9 @@ export function checkForDuplicateInstallations(callback: boolean => void) {
// detect if there are other installations of DevTools present.
// In this case, assume there are no duplicate exensions and show a warning about
// potential conflicts.
console.error(UNRECOGNIZED_EXTENSION_WARNING);
console.error(UNRECOGNIZED_EXTENSION_ERROR);
chrome.devtools.inspectedWindow.eval(
`console.error("${UNRECOGNIZED_EXTENSION_WARNING}")`,
`console.error("${UNRECOGNIZED_EXTENSION_ERROR}")`,
);
callback(false);
break;
Expand All @@ -80,9 +80,9 @@ export function checkForDuplicateInstallations(callback: boolean => void) {
// are other installations of DevTools present.
// In this case, assume there are no duplicate exensions and show a warning about
// potential conflicts.
console.error(UNRECOGNIZED_EXTENSION_WARNING);
console.error(UNRECOGNIZED_EXTENSION_ERROR);
chrome.devtools.inspectedWindow.eval(
`console.error("${UNRECOGNIZED_EXTENSION_WARNING}")`,
`console.error("${UNRECOGNIZED_EXTENSION_ERROR}")`,
);
callback(false);
break;
Expand All @@ -105,7 +105,7 @@ function checkForInstalledExtension(extensionId: string): Promise<boolean> {
return new Promise(resolve => {
chrome.runtime.sendMessage(
extensionId,
EXTENSION_INSTALL_CHECK_MESSAGE,
EXTENSION_INSTALL_CHECK,
response => {
if (__DEBUG__) {
console.log(
Expand Down
4 changes: 3 additions & 1 deletion packages/react-devtools-extensions/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ declare var chrome: any;

export const CURRENT_EXTENSION_ID = chrome.runtime.id;

export const EXTENSION_INSTALL_CHECK_MESSAGE = 'extension-install-check';
export const EXTENSION_INSTALL_CHECK = 'extension-install-check';
export const SHOW_DUPLICATE_EXTENSION_WARNING =
'show-duplicate-extension-warning';

export const CHROME_WEBSTORE_EXTENSION_ID = 'fmkadmapgofadopljbjfkapdkoienihi';
export const INTERNAL_EXTENSION_ID = 'dnjnjgbfilfphmojnmhliehogmojhclc';
Expand Down
35 changes: 34 additions & 1 deletion packages/react-devtools-extensions/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ import {
import DevTools from 'react-devtools-shared/src/devtools/views/DevTools';
import {__DEBUG__} from 'react-devtools-shared/src/constants';
import {logEvent} from 'react-devtools-shared/src/Logger';
import {CURRENT_EXTENSION_ID, EXTENSION_INSTALLATION_TYPE} from './constants';
import {
CURRENT_EXTENSION_ID,
EXTENSION_INSTALLATION_TYPE,
SHOW_DUPLICATE_EXTENSION_WARNING,
} from './constants';
import {checkForDuplicateInstallations} from './checkForDuplicateInstallations';

const LOCAL_STORAGE_SUPPORTS_PROFILING_KEY =
Expand Down Expand Up @@ -108,11 +112,39 @@ function createPanelIfReactLoaded() {
let mostRecentOverrideTab = null;
let render = null;
let root = null;
let warnIfDuplicateInstallation = false;

const tabId = chrome.devtools.inspectedWindow.tabId;

registerDevToolsEventLogger('extension');

function onDuplicateExtensionMessage(message) {
if (message === SHOW_DUPLICATE_EXTENSION_WARNING) {
chrome.runtime.onMessage.removeListener(
onDuplicateExtensionMessage,
);

if (warnIfDuplicateInstallation === true) {
return;
}
warnIfDuplicateInstallation = true;
const errorMessage =
'React Developer Tools: We detected that there are multiple versions of React Developer Tools ' +
'installed and enabled in your browser at the same time, which will cause ' +
'issues while using the extension. ' +
'Please ensure that you have installed and enabled only a single ' +
'version of React Developer Tools before proceeding.';
console.error(errorMessage);
chrome.devtools.inspectedWindow.eval(
`console.error("${errorMessage}")`,
);
if (render != null) {
render();
}
}
}
chrome.runtime.onMessage.addListener(onDuplicateExtensionMessage);

function initBridgeAndStore() {
const port = chrome.runtime.connect({
name: String(tabId),
Expand Down Expand Up @@ -374,6 +406,7 @@ function createPanelIfReactLoaded() {
hookNamesModuleLoaderFunction,
overrideTab,
profilerPortalContainer,
warnIfDuplicateInstallation,
showTabBar: false,
store,
warnIfUnsupportedVersionDetected: true,
Expand Down
4 changes: 4 additions & 0 deletions packages/react-devtools-shared/src/devtools/views/DevTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {SchedulingProfilerContextController} from 'react-devtools-scheduling-pro
import {ModalDialogContextController} from './ModalDialog';
import ReactLogo from './ReactLogo';
import UnsupportedBridgeProtocolDialog from './UnsupportedBridgeProtocolDialog';
import DuplicateInstallationDialog from './DuplicateInstallationDialog';
import UnsupportedVersionDialog from './UnsupportedVersionDialog';
import WarnIfLegacyBackendDetected from './WarnIfLegacyBackendDetected';
import {useLocalStorage} from './hooks';
Expand Down Expand Up @@ -73,6 +74,7 @@ export type Props = {|
enabledInspectedElementContextMenu?: boolean,
showTabBar?: boolean,
store: Store,
warnIfDuplicateInstallation?: boolean,
warnIfLegacyBackendDetected?: boolean,
warnIfUnsupportedVersionDetected?: boolean,
viewAttributeSourceFunction?: ?ViewAttributeSource,
Expand Down Expand Up @@ -132,6 +134,7 @@ export default function DevTools({
profilerPortalContainer,
showTabBar = false,
store,
warnIfDuplicateInstallation = false,
warnIfLegacyBackendDetected = false,
warnIfUnsupportedVersionDetected = false,
viewAttributeSourceFunction,
Expand Down Expand Up @@ -319,6 +322,7 @@ export default function DevTools({
</ViewElementSourceContext.Provider>
</SettingsContextController>
<UnsupportedBridgeProtocolDialog />
{warnIfDuplicateInstallation && <DuplicateInstallationDialog />}
{warnIfLegacyBackendDetected && <WarnIfLegacyBackendDetected />}
{warnIfUnsupportedVersionDetected && <UnsupportedVersionDialog />}
</ModalDialogContextController>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
*/

import * as React from 'react';
import {Fragment, useContext, useEffect} from 'react';
import {isInternalFacebookBuild} from 'react-devtools-feature-flags';
import {ModalDialogContext} from './ModalDialog';

export default function DuplicateInstallationDialog(_: {||}) {
const {dispatch} = useContext(ModalDialogContext);

useEffect(() => {
dispatch({
canBeDismissed: false,
id: 'DuplicateInstallationDialog',
type: 'SHOW',
title: 'Duplicate Installations of DevTools Detected',
content: <DialogContent />,
});
}, []);
return null;
}

function DialogContent(_: {||}) {
return (
<Fragment>
<p>
We detected that there are multiple versions of React Developer Tools
installed and enabled in your browser at the same time, which will cause
issues while using the extension.
</p>
{isInternalFacebookBuild ? (
<p>
Before proceeding, please ensure that the only enabled version of
React Developer Tools is the internal (Chef-installed) version. To
manage your extensions, visit the <code>about://extensions</code> page
in your browser.
</p>
) : (
<p>
Please ensure that you have installed and enabled only a single
version of React Developer Tools before proceeding. To manage your
extensions, visit the <code>about://extensions</code> page in your
browser.
</p>
)}
</Fragment>
);
}

0 comments on commit 4ceb0cb

Please sign in to comment.