Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DO NOT MERGE] Replay React Devtools fork preview #15

Draft
wants to merge 2 commits into
base: react-main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Apply Replay changes
  • Loading branch information
bvaughn authored and markerikson committed Jul 1, 2024
commit 849217d72127dd4c8a5931d758d86a8e0e3a96ce
38 changes: 36 additions & 2 deletions packages/react-devtools-extensions/src/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,56 @@ import type {DevToolsHook} from 'react-devtools-shared/src/backend/types';
import Agent from 'react-devtools-shared/src/backend/agent';
import Bridge from 'react-devtools-shared/src/bridge';
import {initBackend} from 'react-devtools-shared/src/backend';
import setupNativeStyleEditor from 'react-devtools-shared/src/backend/NativeStyleEditor/setupNativeStyleEditor';

import {COMPACT_VERSION_NAME} from './utils';

window.logMessage('RDT initializing');
setup(window.__REACT_DEVTOOLS_GLOBAL_HOOK__);
window.logMessage('RDT setup complete');

function setup(hook: ?DevToolsHook) {
if (hook == null) {
return;
}

const bridge = new Bridge({
listen(fn) {
const listener = event => {
if (
event.source !== window ||
!event.data ||
event.data.source !== 'react-devtools-content-script' ||
!event.data.payload
) {
return;
}
fn(event.data.payload);
};
window.addEventListener('message', listener);
return () => {
window.removeEventListener('message', listener);
};
},
send(event, payload, transferable) {
window.postMessage(
{
source: 'react-devtools-bridge',
payload: {event, payload},
},
'*',
transferable,
);
},
});

const agent = new Agent(bridge);
initBackend(hook, agent, window);

hook.backends.set(COMPACT_VERSION_NAME, {
Agent,
Bridge,
initBackend,
setupNativeStyleEditor,
setupNativeStyleEditor: () => {},
});

hook.emit('devtools-backend-installed', COMPACT_VERSION_NAME);
Expand Down
24 changes: 24 additions & 0 deletions packages/react-devtools-extensions/src/utils.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,30 @@
/* global chrome */

Check failure on line 1 in packages/react-devtools-extensions/src/utils.js

View workflow job for this annotation

GitHub Actions / Run eslint

'chrome' is defined but never used

import type {BrowserTheme} from 'react-devtools-shared/src/devtools/views/DevTools';

Check failure on line 3 in packages/react-devtools-extensions/src/utils.js

View workflow job for this annotation

GitHub Actions / Run eslint

'BrowserTheme' is defined but never used

// REPLAY Our RDT integration is only for Chrome currently
export const IS_EDGE = false; // navigator.userAgent.indexOf('Edg') >= 0;
export const IS_FIREFOX = false; // navigator.userAgent.indexOf('Firefox') >= 0;
export const IS_CHROME = true; //IS_EDGE === false && IS_FIREFOX === false;

export type BrowserName = 'Chrome' | 'Firefox' | 'Edge';

/*
export function getBrowserName(): BrowserName {
if (IS_EDGE) {
return 'Edge';
}
if (IS_FIREFOX) {
return 'Firefox';
}
if (IS_CHROME) {
return 'Chrome';
}
throw new Error(
'Expected browser name to be one of Chrome, Edge or Firefox.',
);
}

export function getBrowserTheme(): BrowserTheme {
if (__IS_CHROME__) {
// chrome.devtools.panels added in Chrome 18.
Expand All @@ -20,6 +43,7 @@
}
}
}
*/

export const COMPACT_VERSION_NAME = 'compact';
export const EXTENSION_CONTAINED_VERSIONS = [COMPACT_VERSION_NAME];
4 changes: 2 additions & 2 deletions packages/react-devtools-extensions/webpack.backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const featureFlagTarget = process.env.FEATURE_FLAG_TARGET || 'extension-oss';

module.exports = {
mode: __DEV__ ? 'development' : 'production',
devtool: false,
devtool: __DEV__ ? 'cheap-module-source-map' : 'source-map',
entry: {
backend: './src/backend.js',
},
Expand All @@ -56,7 +56,7 @@ module.exports = {
},
},
optimization: {
minimize: false,
minimize: true,
},
plugins: [
new Webpack.ProvidePlugin({
Expand Down
16 changes: 8 additions & 8 deletions packages/react-devtools-extensions/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ module.exports = {
mode: __DEV__ ? 'development' : 'production',
devtool: false,
entry: {
background: './src/background/index.js',
backendManager: './src/contentScripts/backendManager.js',
fileFetcher: './src/contentScripts/fileFetcher.js',
main: './src/main/index.js',
panel: './src/panel.js',
proxy: './src/contentScripts/proxy.js',
prepareInjection: './src/contentScripts/prepareInjection.js',
renderer: './src/contentScripts/renderer.js',
// background: './src/background/index.js',
// backendManager: './src/contentScripts/backendManager.js',
// fileFetcher: './src/contentScripts/fileFetcher.js',
// main: './src/main/index.js',
// panel: './src/panel.js',
// proxy: './src/contentScripts/proxy.js',
// prepareInjection: './src/contentScripts/prepareInjection.js',
// renderer: './src/contentScripts/renderer.js',
installHook: './src/contentScripts/installHook.js',
},
output: {
Expand Down
94 changes: 22 additions & 72 deletions packages/react-devtools-shared/src/backend/agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,7 @@
*/

import EventEmitter from '../events';
import throttle from 'lodash.throttle';
import {
SESSION_STORAGE_LAST_SELECTION_KEY,
SESSION_STORAGE_RELOAD_AND_PROFILE_KEY,
SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY,
__DEBUG__,
} from '../constants';
import {
sessionStorageGetItem,
sessionStorageRemoveItem,
sessionStorageSetItem,
} from 'react-devtools-shared/src/storage';
import setupHighlighter from './views/Highlighter';
import {
initialize as setupTraceUpdates,
toggleEnabled as setTraceUpdatesEnabled,
} from './views/TraceUpdates';
import {__DEBUG__} from '../constants';
import {patch as patchConsole} from './console';
import {currentBridgeProtocol} from 'react-devtools-shared/src/bridge';

Expand Down Expand Up @@ -165,26 +149,6 @@
constructor(bridge: BackendBridge) {
super();

if (
sessionStorageGetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY) === 'true'
) {
this._recordChangeDescriptions =
sessionStorageGetItem(
SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY,
) === 'true';
this._isProfiling = true;

sessionStorageRemoveItem(SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY);
sessionStorageRemoveItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY);
}

const persistedSelectionString = sessionStorageGetItem(
SESSION_STORAGE_LAST_SELECTION_KEY,
);
if (persistedSelectionString != null) {
this._persistedSelection = JSON.parse(persistedSelectionString);
}

this._bridge = bridge;

bridge.addListener('clearErrorsAndWarnings', this.clearErrorsAndWarnings);
Expand All @@ -202,7 +166,6 @@
bridge.addListener('overrideError', this.overrideError);
bridge.addListener('overrideSuspense', this.overrideSuspense);
bridge.addListener('overrideValueAtPath', this.overrideValueAtPath);
bridge.addListener('reloadAndProfile', this.reloadAndProfile);
bridge.addListener('renamePath', this.renamePath);
bridge.addListener('setTraceUpdatesEnabled', this.setTraceUpdatesEnabled);
bridge.addListener('startProfiling', this.startProfiling);
Expand Down Expand Up @@ -243,16 +206,30 @@

// Notify the frontend if the backend supports the Storage API (e.g. localStorage).
// If not, features like reload-and-profile will not work correctly and must be disabled.
let isBackendStorageAPISupported = false;

Check failure on line 209 in packages/react-devtools-shared/src/backend/agent.js

View workflow job for this annotation

GitHub Actions / Run eslint

'isBackendStorageAPISupported' is never reassigned. Use 'const' instead
try {
localStorage.getItem('test');
isBackendStorageAPISupported = true;
} catch (error) {}

bridge.send('isBackendStorageAPISupported', isBackendStorageAPISupported);
bridge.send('isSynchronousXHRSupported', isSynchronousXHRSupported());

setupHighlighter(bridge, this);
setupTraceUpdates(this);
window.__RECORD_REPLAY_REACT_DEVTOOLS_SEND_MESSAGE__ = (
inEvent,
inData,
) => {
let rv;
this._bridge = {
send(event, data) {
rv = {event, data};
},
};
try {
this[inEvent](inData);
} catch (err) {
window.logMessage(
`Error executing bridge message '${inEvent}': ${err}, ${err.stack}`,
);
}
return rv;
};
}

get rendererInterfaces(): {[key: RendererID]: RendererInterface, ...} {
Expand Down Expand Up @@ -429,7 +406,6 @@
this._persistedSelection = null;
this._persistedSelectionMatch = null;
renderer.setTrackedPath(null);
this._throttledPersistSelection(rendererID, id);
}

// TODO: If there was a way to change the selected DOM element
Expand Down Expand Up @@ -582,12 +558,6 @@

reloadAndProfile: (recordChangeDescriptions: boolean) => void =
recordChangeDescriptions => {
sessionStorageSetItem(SESSION_STORAGE_RELOAD_AND_PROFILE_KEY, 'true');
sessionStorageSetItem(
SESSION_STORAGE_RECORD_CHANGE_DESCRIPTIONS_KEY,
recordChangeDescriptions ? 'true' : 'false',
);

// This code path should only be hit if the shell has explicitly told the Store that it supports profiling.
// In that case, the shell must also listen for this specific message to know when it needs to reload the app.
// The agent can't do this in a way that is renderer agnostic.
Expand Down Expand Up @@ -640,10 +610,9 @@

setTraceUpdatesEnabled: (traceUpdatesEnabled: boolean) => void =
traceUpdatesEnabled => {
traceUpdatesEnabled = false;
this._traceUpdatesEnabled = traceUpdatesEnabled;

setTraceUpdatesEnabled(traceUpdatesEnabled);

for (const rendererID in this._rendererInterfaces) {
const renderer = ((this._rendererInterfaces[
(rendererID: any)
Expand Down Expand Up @@ -838,23 +807,4 @@
onUnsupportedRenderer(rendererID: number) {
this._bridge.send('unsupportedRendererVersion', rendererID);
}

_throttledPersistSelection: any = throttle(
(rendererID: number, id: number) => {
// This is throttled, so both renderer and selected ID
// might not be available by the time we read them.
// This is why we need the defensive checks here.
const renderer = this._rendererInterfaces[rendererID];
const path = renderer != null ? renderer.getPathForElement(id) : null;
if (path !== null) {
sessionStorageSetItem(
SESSION_STORAGE_LAST_SELECTION_KEY,
JSON.stringify(({rendererID, path}: PersistedSelection)),
);
} else {
sessionStorageRemoveItem(SESSION_STORAGE_LAST_SELECTION_KEY);
}
},
1000,
);
}
5 changes: 3 additions & 2 deletions packages/react-devtools-shared/src/backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import Agent from './agent';

import {attach} from './renderer';
import {attach as attachLegacy} from './legacy/renderer';
import {hasAssignedBackend} from './utils';

import type {DevToolsHook, ReactRenderer, RendererInterface} from './types';
Expand Down Expand Up @@ -78,7 +77,9 @@ export function initBackend(
rendererInterface = attach(hook, id, renderer, global);
} else if (renderer.ComponentTree) {
// react-dom v15
rendererInterface = attachLegacy(hook, id, renderer, global);
// REPLAY We do not support React 15 or earlier for our RDT integration.
// Don't let this connect or save operations.
// rendererInterface = attachLegacy(hook, id, renderer, global);
} else {
// Older react-dom or other unsupported renderer version
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1109,6 +1109,7 @@ export function attach(
getSerializedElementValueByPath,
deletePath,
flushInitialOperations,
flushPendingEvents,
getBestMatchForTrackedPath,
getDisplayNameForFiberID,
getFiberForNative,
Expand Down
Loading
Loading