mirror of
https://github.com/facebook/react.git
synced 2026-02-22 20:01:52 +00:00
Typecheck React DevTools extension main script (#35519)
This commit is contained in:
committed by
GitHub
parent
db71391c5c
commit
cbc4d40663
@@ -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';
|
||||
@@ -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;
|
||||
@@ -71,7 +79,7 @@ function createBridge() {
|
||||
|
||||
bridge.addListener('reloadAppForProfiling', () => {
|
||||
localStorageSetItem(LOCAL_STORAGE_SUPPORTS_PROFILING_KEY, 'true');
|
||||
evalInInspectedWindow('reload', []);
|
||||
evalInInspectedWindow('reload', [], () => {});
|
||||
});
|
||||
|
||||
bridge.addListener(
|
||||
@@ -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;
|
||||
@@ -198,7 +212,7 @@ function createBridgeAndStore() {
|
||||
|
||||
root = createRoot(document.createElement('div'));
|
||||
|
||||
render = (overrideTab = mostRecentOverrideTab) => {
|
||||
render = (overrideTab: TabID | null = mostRecentOverrideTab) => {
|
||||
mostRecentOverrideTab = overrideTab;
|
||||
|
||||
root.render(
|
||||
@@ -227,7 +241,9 @@ function createBridgeAndStore() {
|
||||
};
|
||||
}
|
||||
|
||||
function ensureInitialHTMLIsCleared(container) {
|
||||
function ensureInitialHTMLIsCleared(
|
||||
container: HTMLElement & {_hasInitialHTMLBeenCleared?: boolean},
|
||||
) {
|
||||
if (container._hasInitialHTMLBeenCleared) {
|
||||
return;
|
||||
}
|
||||
@@ -397,13 +413,6 @@ function createSourcesEditorPanel() {
|
||||
logEvent({event_name: 'selected-editor-pane'});
|
||||
}
|
||||
});
|
||||
|
||||
createdPane.onShown.addListener(() => {
|
||||
bridge.emit('extensionEditorPaneShown');
|
||||
});
|
||||
createdPane.onHidden.addListener(() => {
|
||||
bridge.emit('extensionEditorPaneHidden');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
@@ -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');
|
||||
}
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -649,7 +673,7 @@ connectExtensionPort();
|
||||
|
||||
mountReactDevToolsWhenReactHasLoaded();
|
||||
|
||||
function onThemeChanged(themeName) {
|
||||
function onThemeChanged() {
|
||||
// Rerender with the new theme
|
||||
render();
|
||||
}
|
||||
|
||||
6
packages/react-devtools-shared/src/Logger.js
vendored
6
packages/react-devtools-shared/src/Logger.js
vendored
@@ -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>;
|
||||
|
||||
|
||||
4
packages/react-devtools-shared/src/bridge.js
vendored
4
packages/react-devtools-shared/src/bridge.js
vendored
@@ -74,7 +74,7 @@ export const currentBridgeProtocol: BridgeProtocol =
|
||||
|
||||
type ElementAndRendererID = {id: number, rendererID: RendererID};
|
||||
|
||||
type Message = {
|
||||
export type Message = {
|
||||
event: string,
|
||||
payload: any,
|
||||
};
|
||||
@@ -239,7 +239,7 @@ export type BackendEvents = {
|
||||
type StartProfilingParams = ProfilingSettings;
|
||||
type ReloadAndProfilingParams = ProfilingSettings;
|
||||
|
||||
type FrontendEvents = {
|
||||
export type FrontendEvents = {
|
||||
clearErrorsAndWarnings: [{rendererID: RendererID}],
|
||||
clearErrorsForElementID: [ElementAndRendererID],
|
||||
clearHostInstanceHighlight: [],
|
||||
|
||||
Reference in New Issue
Block a user