Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 57 additions & 33 deletions packages/react-devtools-extensions/src/main/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
/* global chrome */

/** @flow */

import type {RootType} from 'react-dom/src/client/ReactDOMRoot';
import type {FrontendBridge, Message} from 'react-devtools-shared/src/bridge';
import type {
TabID,
ViewElementSource,
} from 'react-devtools-shared/src/devtools/views/DevTools';
import type {SourceSelection} from 'react-devtools-shared/src/devtools/views/Editor/EditorPane';
import type {Element} from 'react-devtools-shared/src/frontend/types';

import {createElement} from 'react';
import {flushSync} from 'react-dom';
Expand Down Expand Up @@ -51,9 +59,9 @@ const hookNamesModuleLoaderFunction = () => resolvedParseHookNames;
function createBridge() {
bridge = new Bridge({
listen(fn) {
const bridgeListener = message => fn(message);
const bridgeListener = (message: Message) => fn(message);
// Store the reference so that we unsubscribe from the same object.
const portOnMessage = port.onMessage;
const portOnMessage = ((port: any): ExtensionPort).onMessage;
portOnMessage.addListener(bridgeListener);

lastSubscribedBridgeListener = bridgeListener;
Expand All @@ -71,7 +79,7 @@ function createBridge() {

bridge.addListener('reloadAppForProfiling', () => {
localStorageSetItem(LOCAL_STORAGE_SUPPORTS_PROFILING_KEY, 'true');
evalInInspectedWindow('reload', []);
evalInInspectedWindow('reload', [], () => {});
});

bridge.addListener(
Expand Down Expand Up @@ -176,14 +184,20 @@ function createBridgeAndStore() {
// Otherwise, the Store may miss important initial tree op codes.
injectBackendManager(chrome.devtools.inspectedWindow.tabId);

const viewAttributeSourceFunction = (id, path) => {
const viewAttributeSourceFunction = (
id: Element['id'],
path: Array<string | number>,
) => {
const rendererID = store.getRendererIDForElement(id);
if (rendererID != null) {
viewAttributeSource(rendererID, id, path);
}
};

const viewElementSourceFunction = (source, symbolicatedSource) => {
const viewElementSourceFunction: ViewElementSource = (
source,
symbolicatedSource,
) => {
const [, sourceURL, line, column] = symbolicatedSource
? symbolicatedSource
: source;
Expand All @@ -198,7 +212,7 @@ function createBridgeAndStore() {

root = createRoot(document.createElement('div'));

render = (overrideTab = mostRecentOverrideTab) => {
render = (overrideTab: TabID | null = mostRecentOverrideTab) => {
mostRecentOverrideTab = overrideTab;

root.render(
Expand Down Expand Up @@ -227,7 +241,9 @@ function createBridgeAndStore() {
};
}

function ensureInitialHTMLIsCleared(container) {
function ensureInitialHTMLIsCleared(
container: HTMLElement & {_hasInitialHTMLBeenCleared?: boolean},
) {
if (container._hasInitialHTMLBeenCleared) {
return;
}
Expand Down Expand Up @@ -397,13 +413,6 @@ function createSourcesEditorPanel() {
logEvent({event_name: 'selected-editor-pane'});
}
});

createdPane.onShown.addListener(() => {
bridge.emit('extensionEditorPaneShown');
});
createdPane.onHidden.addListener(() => {
bridge.emit('extensionEditorPaneHidden');
});
});
}

Expand Down Expand Up @@ -479,10 +488,10 @@ function performInTabNavigationCleanup() {
// Do not clean mostRecentOverrideTab on purpose, so we remember last opened
// React DevTools tab, when user does in-tab navigation

store = null;
bridge = null;
render = null;
root = null;
store = (null: $FlowFixMe);
bridge = (null: $FlowFixMe);
render = (null: $FlowFixMe);
root = (null: $FlowFixMe);
}

function performFullCleanup() {
Expand All @@ -504,18 +513,18 @@ function performFullCleanup() {
componentsPortalContainer = null;
profilerPortalContainer = null;
suspensePortalContainer = null;
root = null;
root = (null: $FlowFixMe);

mostRecentOverrideTab = null;
store = null;
bridge = null;
render = null;
store = (null: $FlowFixMe);
bridge = (null: $FlowFixMe);
render = (null: $FlowFixMe);

port?.disconnect();
port = null;
port = (null: $FlowFixMe);
}

function connectExtensionPort() {
function connectExtensionPort(): void {
if (port) {
throw new Error('DevTools port was already connected');
}
Expand All @@ -539,7 +548,7 @@ function connectExtensionPort() {
// so, when we call `port.disconnect()` from this script,
// this should not trigger this callback and port reconnection
port.onDisconnect.addListener(() => {
port = null;
port = (null: $FlowFixMe);
connectExtensionPort();
});
}
Expand Down Expand Up @@ -593,9 +602,9 @@ function mountReactDevToolsWhenReactHasLoaded() {
);
}

let bridge = null;
let bridge: FrontendBridge = (null: $FlowFixMe);
let lastSubscribedBridgeListener = null;
let store = null;
let store: Store = (null: $FlowFixMe);

let profilingData = null;

Expand All @@ -610,13 +619,28 @@ let suspensePortalContainer = null;
let editorPortalContainer = null;
let inspectedElementPortalContainer = null;

let mostRecentOverrideTab = null;
let render = null;
let root = null;
let mostRecentOverrideTab: null | TabID = null;
let render: (overrideTab?: TabID) => void = (null: $FlowFixMe);
let root: RootType = (null: $FlowFixMe);

let currentSelectedSource: null | SourceSelection = null;

let port = null;
type ExtensionEvent = {
addListener(callback: (message: Message, port: ExtensionPort) => void): void,
removeListener(
callback: (message: Message, port: ExtensionPort) => void,
): void,
};

/** https://developer.chrome.com/docs/extensions/reference/api/runtime#type-Port */
type ExtensionPort = {
onDisconnect: ExtensionEvent,
onMessage: ExtensionEvent,
postMessage(message: mixed, transferable?: Array<mixed>): void,
disconnect(): void,
};

let port: ExtensionPort = (null: $FlowFixMe);

// In case when multiple navigation events emitted in a short period of time
// This debounced callback primarily used to avoid mounting React DevTools multiple times, which results
Expand Down Expand Up @@ -649,7 +673,7 @@ connectExtensionPort();

mountReactDevToolsWhenReactHasLoaded();

function onThemeChanged(themeName) {
function onThemeChanged() {
// Rerender with the new theme
render();
}
Expand Down
6 changes: 5 additions & 1 deletion packages/react-devtools-shared/src/Logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@ export type LoggerEvent =
+value: any,
...
},
};
}
| {
+event_name: 'selected-editor-pane',
}
| {+event_name: 'selected-inspected-element-pane'};

export type LogFunction = LoggerEvent => void | Promise<void>;

Expand Down
4 changes: 2 additions & 2 deletions packages/react-devtools-shared/src/bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export const currentBridgeProtocol: BridgeProtocol =

type ElementAndRendererID = {id: number, rendererID: RendererID};

type Message = {
export type Message = {
event: string,
payload: any,
};
Expand Down Expand Up @@ -239,7 +239,7 @@ export type BackendEvents = {
type StartProfilingParams = ProfilingSettings;
type ReloadAndProfilingParams = ProfilingSettings;

type FrontendEvents = {
export type FrontendEvents = {
clearErrorsAndWarnings: [{rendererID: RendererID}],
clearErrorsForElementID: [ElementAndRendererID],
clearHostInstanceHighlight: [],
Expand Down
Loading