diff --git a/packages/react-devtools-extensions/src/inject.js b/packages/react-devtools-extensions/src/inject.js new file mode 100644 index 0000000000000..938e2cf7eb227 --- /dev/null +++ b/packages/react-devtools-extensions/src/inject.js @@ -0,0 +1,24 @@ +/* global chrome */ + +export default function inject(scriptName: string, done: ?Function) { + const source = ` + // the prototype stuff is in case document.createElement has been modified + (function () { + var script = document.constructor.prototype.createElement.call(document, 'script'); + script.src = "${scriptName}"; + script.charset = "utf-8"; + document.documentElement.appendChild(script); + script.parentNode.removeChild(script); + })() + `; + + chrome.devtools.inspectedWindow.eval(source, function(response, error) { + if (error) { + console.log(error); + } + + if (typeof done === 'function') { + done(); + } + }); +} diff --git a/packages/react-devtools-extensions/src/injectGlobalHook.js b/packages/react-devtools-extensions/src/injectGlobalHook.js index 2347671d24a5a..b56f9a299b378 100644 --- a/packages/react-devtools-extensions/src/injectGlobalHook.js +++ b/packages/react-devtools-extensions/src/injectGlobalHook.js @@ -24,26 +24,16 @@ let lastDetectionResult; // So instead, the hook will use postMessage() to pass message to us here. // And when this happens, we'll send a message to the "background page". window.addEventListener('message', function(evt) { - if (evt.source === window && evt.data) { - if (evt.data.source === 'react-devtools-detector') { - lastDetectionResult = { - hasDetectedReact: true, - reactBuildType: evt.data.reactBuildType, - }; - chrome.runtime.sendMessage(lastDetectionResult); - } else if (evt.data.source === 'react-devtools-inject-backend') { - // The backend is injected by the content script to avoid CSP and Trusted Types violations, - // since content scripts can modify the DOM and are not subject to the page's policies. - // The prototype stuff is in case document.createElement has been modified. - const script = document.constructor.prototype.createElement.call( - document, - 'script', - ); - script.src = chrome.runtime.getURL('build/backend.js'); - script.charset = 'utf-8'; - document.documentElement.appendChild(script); - script.parentNode.removeChild(script); - } + if ( + evt.source === window && + evt.data && + evt.data.source === 'react-devtools-detector' + ) { + lastDetectionResult = { + hasDetectedReact: true, + reactBuildType: evt.data.reactBuildType, + }; + chrome.runtime.sendMessage(lastDetectionResult); } }); diff --git a/packages/react-devtools-extensions/src/main.js b/packages/react-devtools-extensions/src/main.js index d12f002b843a0..7d786e0321917 100644 --- a/packages/react-devtools-extensions/src/main.js +++ b/packages/react-devtools-extensions/src/main.js @@ -4,6 +4,7 @@ import {createElement} from 'react'; import {unstable_createRoot as createRoot, flushSync} from 'react-dom'; import Bridge from 'react-devtools-shared/src/bridge'; import Store from 'react-devtools-shared/src/devtools/store'; +import inject from './inject'; import { createViewElementSource, getBrowserName, @@ -134,14 +135,7 @@ function createPanelIfReactLoaded() { // Initialize the backend only once the Store has been initialized. // Otherwise the Store may miss important initial tree op codes. - chrome.devtools.inspectedWindow.eval( - `window.postMessage({ source: 'react-devtools-inject-backend' });`, - function(response, evalError) { - if (evalError) { - console.log(evalError); - } - }, - ); + inject(chrome.runtime.getURL('build/backend.js')); const viewElementSourceFunction = createViewElementSource( bridge, @@ -161,6 +155,7 @@ function createPanelIfReactLoaded() { overrideTab, profilerPortalContainer, showTabBar: false, + showWelcomeToTheNewDevToolsDialog: true, store, viewElementSourceFunction, }),