Skip to content

Commit

Permalink
fix[devtools/extension]: added a workaround for proxy content script …
Browse files Browse the repository at this point in the history
…injection in firefox
  • Loading branch information
hoxyq committed Sep 14, 2023
1 parent 54c2f2a commit d16301e
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 60 deletions.
6 changes: 6 additions & 0 deletions packages/react-devtools-extensions/src/background/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ function isNumeric(str: string): boolean {

chrome.runtime.onConnect.addListener(port => {
if (port.name === 'proxy') {
// Might not be present for restricted pages in Firefox
if (port.sender?.tab?.id == null) {
// Not disconnecting it, so it would not reconnect
return;
}

// Proxy content script is executed in tab, so it should have it specified.
const tabId = port.sender.tab.id;

Expand Down
134 changes: 74 additions & 60 deletions packages/react-devtools-extensions/src/contentScripts/proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,77 +2,91 @@

'use strict';

let port = null;
let backendInitialized: boolean = false;

connectPort();
sayHelloToBackendManager();

// The backend waits to install the global hook until notified by the content script.
// In the event of a page reload, the content script might be loaded before the backend manager is injected.
// Because of this we need to poll the backend manager until it has been initialized.
const intervalID = setInterval(() => {
if (backendInitialized) {
clearInterval(intervalID);
} else {
sayHelloToBackendManager();
window.addEventListener('unload', function ({target}) {
if (target !== window.document) {
return;
}
}, 500);

function sayHelloToBackendManager() {
window.postMessage(
{
source: 'react-devtools-content-script',
hello: true,
},
'*',
);
}

function handleMessageFromDevtools(message) {
window.postMessage(
{
source: 'react-devtools-content-script',
payload: message,
},
'*',
);
}
delete window.__REACT_DEVTOOLS_PROXY_INJECTED__;
});

// Firefox's behaviour for injecting this content script can be unpredictable
// While navigating the history, some content scripts might not be re-injected and still be alive
if (!window.__REACT_DEVTOOLS_PROXY_INJECTED__) {
window.__REACT_DEVTOOLS_PROXY_INJECTED__ = true;

let port = null;
let backendInitialized: boolean = false;

function handleMessageFromPage(event) {
if (event.source === window && event.data) {
// This is a message from a bridge (initialized by a devtools backend)
if (event.data.source === 'react-devtools-bridge') {
backendInitialized = true;
connectPort();
sayHelloToBackendManager();

port.postMessage(event.data.payload);
// The backend waits to install the global hook until notified by the content script.
// In the event of a page reload, the content script might be loaded before the backend manager is injected.
// Because of this we need to poll the backend manager until it has been initialized.
const intervalID = setInterval(() => {
if (backendInitialized) {
clearInterval(intervalID);
} else {
sayHelloToBackendManager();
}
}, 500);

function sayHelloToBackendManager() {
window.postMessage(
{
source: 'react-devtools-content-script',
hello: true,
},
'*',
);
}

function handleMessageFromDevtools(message) {
window.postMessage(
{
source: 'react-devtools-content-script',
payload: message,
},
'*',
);
}

function handleMessageFromPage(event) {
if (event.source === window && event.data) {
// This is a message from a bridge (initialized by a devtools backend)
if (event.data.source === 'react-devtools-bridge') {
backendInitialized = true;

// This is a message from the backend manager
if (event.data.source === 'react-devtools-backend-manager') {
chrome.runtime.sendMessage({
payload: event.data.payload,
});
port.postMessage(event.data.payload);
}

// This is a message from the backend manager
if (event.data.source === 'react-devtools-backend-manager') {
chrome.runtime.sendMessage({
payload: event.data.payload,
});
}
}
}
}

function handleDisconnect() {
window.removeEventListener('message', handleMessageFromPage);
port = null;
function handleDisconnect() {
window.removeEventListener('message', handleMessageFromPage);
port = null;

connectPort();
}
connectPort();
}

// Creates port from application page to the React DevTools' service worker
// Which then connects it with extension port
function connectPort() {
port = chrome.runtime.connect({
name: 'proxy',
});
// Creates port from application page to the React DevTools' service worker
// Which then connects it with extension port
function connectPort() {
port = chrome.runtime.connect({
name: 'proxy',
});

window.addEventListener('message', handleMessageFromPage);
window.addEventListener('message', handleMessageFromPage);

port.onMessage.addListener(handleMessageFromDevtools);
port.onDisconnect.addListener(handleDisconnect);
port.onMessage.addListener(handleMessageFromDevtools);
port.onDisconnect.addListener(handleDisconnect);
}
}

0 comments on commit d16301e

Please sign in to comment.