New NPM package react-devtools-inline (#363)
This commit is contained in:
parent
6f1e283b76
commit
dc8580e64d
|
@ -5,6 +5,7 @@ shells/browser/firefox/build
|
|||
shells/browser/shared/build
|
||||
shells/dev/dist
|
||||
packages/react-devtools-core/dist
|
||||
packages/react-devtools-inline/dist
|
||||
vendor
|
||||
*.js.snap
|
||||
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
/shells/browser/firefox/*.pem
|
||||
/shells/browser/shared/build
|
||||
/packages/react-devtools-core/dist
|
||||
/packages/react-devtools-inline/dist
|
||||
/shells/dev/dist
|
||||
build
|
||||
/node_modules
|
||||
/packages/react-devtools-core/node_modules/
|
||||
/packages/react-devtools/node_modules/
|
||||
/packages/react-devtools-core/node_modules
|
||||
/packages/react-devtools-inline/node_modules
|
||||
/packages/react-devtools/node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
.DS_Store
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
"scripts": {
|
||||
"build:core:backend": "cd ./packages/react-devtools-core && yarn build:backend",
|
||||
"build:core:standalone": "cd ./packages/react-devtools-core && yarn build:standalone",
|
||||
"build:core": "cd ./packages/react-devtools-core && yarn build",
|
||||
"build:inline": "cd ./packages/react-devtools-inline && yarn build",
|
||||
"build:demo": "cd ./shells/dev && cross-env NODE_ENV=development cross-env TARGET=remote webpack --config webpack.config.js",
|
||||
"build:extension": "cross-env NODE_ENV=production yarn run build:extension:chrome && yarn run build:extension:firefox",
|
||||
"build:extension:dev": "cross-env NODE_ENV=development yarn run build:extension:chrome && yarn run build:extension:firefox",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "react-devtools-core",
|
||||
"version": "4.0.0-alpha.6",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Use react-devtools outside of the browser",
|
||||
"license": "MIT",
|
||||
"main": "./dist/backend.js",
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
# `react-devtools-inline`
|
||||
|
||||
React DevTools implementation for embedding within a browser-based IDE (e.g. [CodeSandbox](https://codesandbox.io/), [StackBlitz](https://stackblitz.com/)).
|
||||
|
||||
This is a low-level package. If you're looking for the standalone DevTools app, **use the `react-devtools` package instead.**
|
||||
|
||||
## Usage
|
||||
|
||||
This package exports two entry points: a frontend (to be run in the main `window`) and a backend (to be installed and run within an `iframe`<sup>1</sup>).
|
||||
|
||||
The frontend and backend can be initialized in any order, but **the backend must not be activated until after the frontend has been initialized**. Because of this, the simplest sequence is:
|
||||
|
||||
1. Frontend (DevTools interface) initialized in the main `window`.
|
||||
1. Backend initialized in an `iframe`.
|
||||
1. Backend activated.
|
||||
|
||||
<sup>1</sup> Sandboxed iframes are supported.
|
||||
|
||||
## API
|
||||
|
||||
### `react-devtools-inline/backend`
|
||||
|
||||
* **`initialize(contentWindow)`** -
|
||||
Installs the global hook on the window. This hook is how React and DevTools communicate. **This method must be called before React is loaded.** (This means before any `import` or `require` statements!)
|
||||
* **`activate(contentWindow)`** -
|
||||
Lets the backend know when the frontend is ready. It should not be called until after the frontend has been initialized, else the frontend might miss important tree-initialization events.
|
||||
|
||||
```js
|
||||
import { activate, initialize } from 'react-devtools-inline/backend';
|
||||
|
||||
// Call this before importing React (or any other packages that might import React).
|
||||
initialize();
|
||||
|
||||
// Call this only once the frontend has been initialized.
|
||||
activate();
|
||||
```
|
||||
|
||||
### `react-devtools-inline/frontend`
|
||||
|
||||
* **`initialize(contentWindow)`** -
|
||||
Configures the DevTools interface to listen to the `window` the backend was injected into. This method returns a React component that can be rendered directly.
|
||||
|
||||
```js
|
||||
import { initialize } from 'react-devtools-inline/frontend';
|
||||
|
||||
// This should be the iframe the backend hook has been installed in.
|
||||
const iframe = document.getElementById(frameID);
|
||||
const contentWindow = iframe.contentWindow;
|
||||
|
||||
// This returns a React component that can be rendered into your app.
|
||||
// <DevTools {...props} />
|
||||
const DevTools = initialize(contentWindow);
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Configuring a same-origin `iframe`
|
||||
|
||||
The simplest way to use this package is to install the hook from the parent `window`. This is possible if the `iframe` is not sandboxed and there are no cross-origin restrictions.
|
||||
|
||||
```js
|
||||
import {
|
||||
activate as activateBackend,
|
||||
initialize as initializeBackend
|
||||
} from 'react-devtools-inline/backend';
|
||||
import { initialize as initializeFrontend } from 'react-devtools-inline/frontend';
|
||||
|
||||
// The React app you want to inspect with DevTools is running within this iframe:
|
||||
const iframe = document.getElementById('target');
|
||||
const { contentWindow } = iframe;
|
||||
|
||||
// Installs the global hook into the iframe.
|
||||
// This be called before React is loaded into that frame.
|
||||
initializeBackend(contentWindow);
|
||||
|
||||
// React application can be injected into <iframe> at any time now...
|
||||
|
||||
// Initialize DevTools UI to listen to the hook we just installed.
|
||||
// This returns a React component we can render anywhere in the parent window.
|
||||
const DevTools = initializeFrontend(contentWindow);
|
||||
|
||||
// <DevTools /> interface can be rendered in the parent window at any time now...
|
||||
|
||||
// Let the backend know the frontend is ready and listening.
|
||||
activateBackend(contentWindow);
|
||||
```
|
||||
|
||||
### Configuring a sandboxed `iframe`
|
||||
|
||||
Sandboxed `iframe`s are also supported but require more complex initialization.
|
||||
|
||||
**`iframe.html`**
|
||||
```js
|
||||
import { activate, initialize } from 'react-devtools-inline/backend';
|
||||
|
||||
// The DevTooks hook needs to be installed before React is even required!
|
||||
// The safest way to do this is probably to install it in a separate script tag.
|
||||
initialize(window);
|
||||
|
||||
// Wait for the frontend to let us know that it's ready.
|
||||
window.addEventListener('message', ({ data }) => {
|
||||
switch (data.type) {
|
||||
case 'activate':
|
||||
activate(window);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**`main-window.html`**
|
||||
```js
|
||||
import { initialize } from 'react-devtools-inline/frontend';
|
||||
|
||||
const iframe = document.getElementById('target');
|
||||
const { contentWindow } = iframe;
|
||||
|
||||
// Initialize DevTools UI to listen to the iframe.
|
||||
// This returns a React component we can render anywhere in the main window.
|
||||
const DevTools = initialize(contentWindow);
|
||||
|
||||
// Let the backend know to initialize itself.
|
||||
// We can't do this directly because the iframe is sandboxed.
|
||||
// Only initialize the backend once the DevTools frontend has been initialized.
|
||||
iframe.onload = () => {
|
||||
contentWindow.postMessage(
|
||||
{
|
||||
type: 'activate',
|
||||
},
|
||||
'*'
|
||||
);
|
||||
};
|
||||
```
|
|
@ -0,0 +1 @@
|
|||
module.exports = require('./dist/backend');
|
|
@ -0,0 +1 @@
|
|||
module.exports = require('./dist/frontend');
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"name": "react-devtools-inline",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Embed react-devtools within a website",
|
||||
"license": "MIT",
|
||||
"main": "./dist/backend.js",
|
||||
"repository": {
|
||||
"url": "https://github.com/bvaughn/react-devtools-experimental.git",
|
||||
"type": "git"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"backend.js",
|
||||
"frontend.js"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "cross-env NODE_ENV=production webpack --config webpack.config.js",
|
||||
"prepublish": "yarn run build",
|
||||
"start": "cross-env NODE_ENV=development webpack --config webpack.config.js --watch"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"cross-env": "^3.1.4"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/** @flow */
|
||||
|
||||
import Agent from 'src/backend/agent';
|
||||
import Bridge from 'src/bridge';
|
||||
import { initBackend } from 'src/backend';
|
||||
import { installHook } from 'src/hook';
|
||||
import setupNativeStyleEditor from 'src/backend/NativeStyleEditor/setupNativeStyleEditor';
|
||||
import {
|
||||
MESSAGE_TYPE_GET_SAVED_PREFERENCES,
|
||||
MESSAGE_TYPE_SAVED_PREFERENCES,
|
||||
} from './constants';
|
||||
|
||||
function startActivation(contentWindow: window) {
|
||||
const { parent } = contentWindow;
|
||||
|
||||
const onMessage = ({ data }) => {
|
||||
switch (data.type) {
|
||||
case MESSAGE_TYPE_SAVED_PREFERENCES:
|
||||
// This is the only message we're listening for,
|
||||
// so it's safe to cleanup after we've received it.
|
||||
contentWindow.removeEventListener('message', onMessage);
|
||||
|
||||
const { appendComponentStack, componentFilters } = data;
|
||||
|
||||
contentWindow.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = appendComponentStack;
|
||||
contentWindow.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = componentFilters;
|
||||
|
||||
// TRICKY
|
||||
// The backend entry point may be required in the context of an iframe or the parent window.
|
||||
// If it's required within the parent window, store the saved values on it as well,
|
||||
// since the injected renderer interface will read from window.
|
||||
// Technically we don't need to store them on the contentWindow in this case,
|
||||
// but it doesn't really hurt anything to store them there too.
|
||||
if (contentWindow !== window) {
|
||||
window.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = appendComponentStack;
|
||||
window.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = componentFilters;
|
||||
}
|
||||
|
||||
finishActivation(contentWindow);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
contentWindow.addEventListener('message', onMessage);
|
||||
|
||||
// The backend may be unable to read saved preferences directly,
|
||||
// because they are stored in localStorage within the context of the extension (on the frontend).
|
||||
// Instead it relies on the extension to pass preferences through.
|
||||
// Because we might be in a sandboxed iframe, we have to ask for them by way of postMessage().
|
||||
parent.postMessage({ type: MESSAGE_TYPE_GET_SAVED_PREFERENCES }, '*');
|
||||
}
|
||||
|
||||
function finishActivation(contentWindow: window) {
|
||||
const { parent } = contentWindow;
|
||||
|
||||
const bridge = new Bridge({
|
||||
listen(fn) {
|
||||
const onMessage = event => {
|
||||
fn(event.data);
|
||||
};
|
||||
contentWindow.addEventListener('message', onMessage);
|
||||
return () => {
|
||||
contentWindow.removeEventListener('message', onMessage);
|
||||
};
|
||||
},
|
||||
send(event: string, payload: any, transferable?: Array<any>) {
|
||||
parent.postMessage({ event, payload }, '*', transferable);
|
||||
},
|
||||
});
|
||||
|
||||
const agent = new Agent(bridge);
|
||||
|
||||
const hook = contentWindow.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
||||
|
||||
initBackend(hook, agent, contentWindow);
|
||||
|
||||
// Setup React Native style editor if a renderer like react-native-web has injected it.
|
||||
if (!!hook.resolveRNStyle) {
|
||||
setupNativeStyleEditor(
|
||||
bridge,
|
||||
agent,
|
||||
hook.resolveRNStyle,
|
||||
hook.nativeStyleEditorValidAttributes
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function activate(contentWindow: window): void {
|
||||
startActivation(contentWindow);
|
||||
}
|
||||
|
||||
export function initialize(contentWindow: window): void {
|
||||
installHook(contentWindow);
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
/** @flow */
|
||||
|
||||
export const MESSAGE_TYPE_GET_SAVED_PREFERENCES =
|
||||
'React::DevTools::getSavedPreferences';
|
||||
export const MESSAGE_TYPE_SAVED_PREFERENCES =
|
||||
'React::DevTools::savedPreferences';
|
|
@ -0,0 +1,68 @@
|
|||
/** @flow */
|
||||
|
||||
import React, { forwardRef } from 'react';
|
||||
import Bridge from 'src/bridge';
|
||||
import Store from 'src/devtools/store';
|
||||
import DevTools from 'src/devtools/views/DevTools';
|
||||
import { getSavedComponentFilters, getAppendComponentStack } from 'src/utils';
|
||||
import {
|
||||
MESSAGE_TYPE_GET_SAVED_PREFERENCES,
|
||||
MESSAGE_TYPE_SAVED_PREFERENCES,
|
||||
} from './constants';
|
||||
|
||||
import type { FrontendBridge } from 'src/bridge';
|
||||
import type { Props } from 'src/devtools/views/DevTools';
|
||||
|
||||
export function initialize(
|
||||
contentWindow: window
|
||||
): React$AbstractComponent<Props, mixed> {
|
||||
const onMessage = ({ data, origin, source }) => {
|
||||
switch (data.type) {
|
||||
case MESSAGE_TYPE_GET_SAVED_PREFERENCES:
|
||||
// This is the only message we're listening for,
|
||||
// so it's safe to cleanup after we've received it.
|
||||
window.removeEventListener('message', onMessage);
|
||||
|
||||
// The renderer interface can't read saved preferences directly,
|
||||
// because they are stored in localStorage within the context of the extension.
|
||||
// Instead it relies on the extension to pass them through.
|
||||
contentWindow.postMessage(
|
||||
{
|
||||
type: MESSAGE_TYPE_SAVED_PREFERENCES,
|
||||
appendComponentStack: getAppendComponentStack(),
|
||||
componentFilters: getSavedComponentFilters(),
|
||||
},
|
||||
'*'
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('message', onMessage);
|
||||
|
||||
const bridge: FrontendBridge = new Bridge({
|
||||
listen(fn) {
|
||||
const onMessage = ({ data }) => {
|
||||
fn(data);
|
||||
};
|
||||
window.addEventListener('message', onMessage);
|
||||
return () => {
|
||||
window.removeEventListener('message', onMessage);
|
||||
};
|
||||
},
|
||||
send(event: string, payload: any, transferable?: Array<any>) {
|
||||
contentWindow.postMessage({ event, payload }, '*', transferable);
|
||||
},
|
||||
});
|
||||
|
||||
const store: Store = new Store(bridge);
|
||||
|
||||
const ForwardRef = forwardRef<Props, mixed>((props, ref) => (
|
||||
<DevTools ref={ref} bridge={bridge} store={store} {...props} />
|
||||
));
|
||||
ForwardRef.displayName = 'DevTools';
|
||||
|
||||
return ForwardRef;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
const { resolve } = require('path');
|
||||
const { DefinePlugin } = require('webpack');
|
||||
const { getGitHubURL, getVersionString } = require('../../shells/utils');
|
||||
|
||||
const NODE_ENV = process.env.NODE_ENV;
|
||||
if (!NODE_ENV) {
|
||||
console.error('NODE_ENV not set');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const __DEV__ = true; // NODE_ENV === 'development';
|
||||
|
||||
const GITHUB_URL = getGitHubURL();
|
||||
const DEVTOOLS_VERSION = getVersionString();
|
||||
|
||||
module.exports = {
|
||||
mode: __DEV__ ? 'development' : 'production',
|
||||
devtool: false,
|
||||
entry: {
|
||||
backend: './src/backend.js',
|
||||
frontend: './src/frontend.js',
|
||||
},
|
||||
output: {
|
||||
path: __dirname + '/dist',
|
||||
filename: '[name].js',
|
||||
library: '[name]',
|
||||
libraryTarget: 'commonjs2',
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
src: resolve(__dirname, '../../src'),
|
||||
},
|
||||
},
|
||||
externals: {
|
||||
react: 'react',
|
||||
'react-dom': 'react-dom',
|
||||
scheduler: 'scheduler',
|
||||
},
|
||||
plugins: [
|
||||
new DefinePlugin({
|
||||
__DEV__: __DEV__,
|
||||
'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`,
|
||||
'process.env.GITHUB_URL': `"${GITHUB_URL}"`,
|
||||
'process.env.NODE_ENV': `"${NODE_ENV}"`,
|
||||
}),
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
configFile: resolve(__dirname, '../../babel.config.js'),
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'style-loader',
|
||||
},
|
||||
{
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
modules: true,
|
||||
localIdentName: '[local]___[hash:base64:5]',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "react-devtools",
|
||||
"version": "4.0.0-alpha.6",
|
||||
"version": "4.0.0-alpha.7",
|
||||
"description": "Use react-devtools outside of the browser",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
@ -25,7 +25,7 @@
|
|||
"electron": "^5.0.0",
|
||||
"ip": "^1.1.4",
|
||||
"minimist": "^1.2.0",
|
||||
"react-devtools-core": "4.0.0-alpha.6",
|
||||
"react-devtools-core": "4.0.0-alpha.7",
|
||||
"update-notifier": "^2.1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,6 @@ function createPanelIfReactLoaded() {
|
|||
|
||||
let componentsPortalContainer = null;
|
||||
let profilerPortalContainer = null;
|
||||
let settingsPortalContainer = null;
|
||||
|
||||
let cloneStyleTags = null;
|
||||
let mostRecentOverrideTab = null;
|
||||
|
@ -142,7 +141,6 @@ function createPanelIfReactLoaded() {
|
|||
componentsPortalContainer,
|
||||
overrideTab,
|
||||
profilerPortalContainer,
|
||||
settingsPortalContainer,
|
||||
showTabBar: false,
|
||||
showWelcomeToTheNewDevToolsDialog: true,
|
||||
store,
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
/** @flow */
|
||||
|
||||
import Agent from 'src/backend/agent';
|
||||
import Bridge from 'src/bridge';
|
||||
import { initBackend } from 'src/backend';
|
||||
import setupNativeStyleEditor from 'src/backend/NativeStyleEditor/setupNativeStyleEditor';
|
||||
|
||||
const bridge = new Bridge({
|
||||
listen(fn) {
|
||||
const listener = event => {
|
||||
fn(event.data);
|
||||
};
|
||||
window.addEventListener('message', listener);
|
||||
return () => {
|
||||
window.removeEventListener('message', listener);
|
||||
};
|
||||
},
|
||||
send(event: string, payload: any, transferable?: Array<any>) {
|
||||
window.parent.postMessage({ event, payload }, '*', transferable);
|
||||
},
|
||||
});
|
||||
|
||||
const agent = new Agent(bridge);
|
||||
|
||||
const hook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
||||
|
||||
initBackend(hook, agent, window.parent);
|
||||
|
||||
// Setup React Native style editor if a renderer like react-native-web has injected it.
|
||||
if (!!hook.resolveRNStyle) {
|
||||
setupNativeStyleEditor(
|
||||
bridge,
|
||||
agent,
|
||||
hook.resolveRNStyle,
|
||||
hook.nativeStyleEditorValidAttributes
|
||||
);
|
||||
}
|
|
@ -3,24 +3,21 @@
|
|||
import { createElement } from 'react';
|
||||
// $FlowFixMe Flow does not yet know about createRoot()
|
||||
import { unstable_createRoot as createRoot } from 'react-dom';
|
||||
import Bridge from 'src/bridge';
|
||||
import { installHook } from 'src/hook';
|
||||
import {
|
||||
activate as activateBackend,
|
||||
initialize as initializeBackend,
|
||||
} from 'react-devtools-inline/backend';
|
||||
import { initialize as initializeFrontend } from 'react-devtools-inline/frontend';
|
||||
import { initDevTools } from 'src/devtools';
|
||||
import Store from 'src/devtools/store';
|
||||
import DevTools from 'src/devtools/views/DevTools';
|
||||
import { getSavedComponentFilters, getAppendComponentStack } from 'src/utils';
|
||||
|
||||
const iframe = ((document.getElementById('target'): any): HTMLIFrameElement);
|
||||
|
||||
const { contentDocument, contentWindow } = iframe;
|
||||
|
||||
// The renderer interface can't read saved component filters directly,
|
||||
// because they are stored in localStorage within the context of the extension.
|
||||
// Instead it relies on the extension to pass filters through.
|
||||
contentWindow.__REACT_DEVTOOLS_COMPONENT_FILTERS__ = getSavedComponentFilters();
|
||||
contentWindow.__REACT_DEVTOOLS_APPEND_COMPONENT_STACK__ = getAppendComponentStack();
|
||||
// Helps with positioning Overlay UI.
|
||||
contentWindow.__REACT_DEVTOOLS_TARGET_WINDOW__ = window;
|
||||
|
||||
installHook(contentWindow);
|
||||
initializeBackend(contentWindow);
|
||||
|
||||
const container = ((document.getElementById('devtools'): any): HTMLElement);
|
||||
|
||||
|
@ -48,46 +45,21 @@ mountButton.addEventListener('click', function() {
|
|||
inject('dist/app.js', () => {
|
||||
initDevTools({
|
||||
connect(cb) {
|
||||
const bridge = new Bridge({
|
||||
listen(fn) {
|
||||
const listener = ({ data }) => {
|
||||
fn(data);
|
||||
};
|
||||
// Preserve the reference to the window we subscribe to, so we can unsubscribe from it when required.
|
||||
const contentWindowParent = contentWindow.parent;
|
||||
contentWindowParent.addEventListener('message', listener);
|
||||
return () => {
|
||||
contentWindowParent.removeEventListener('message', listener);
|
||||
};
|
||||
},
|
||||
send(event: string, payload: any, transferable?: Array<any>) {
|
||||
contentWindow.postMessage({ event, payload }, '*', transferable);
|
||||
},
|
||||
});
|
||||
const DevTools = initializeFrontend(contentWindow);
|
||||
|
||||
cb(bridge);
|
||||
|
||||
const store = new Store(bridge);
|
||||
// Activate the backend only once the DevTools frontend Store has been initialized.
|
||||
// Otherwise the Store may miss important initial tree op codes.
|
||||
activateBackend(contentWindow);
|
||||
|
||||
const root = createRoot(container);
|
||||
const batch = root.createBatch();
|
||||
batch.render(
|
||||
root.render(
|
||||
createElement(DevTools, {
|
||||
bridge,
|
||||
browserTheme: 'light',
|
||||
showTabBar: true,
|
||||
showWelcomeToTheNewDevToolsDialog: true,
|
||||
store,
|
||||
warnIfLegacyBackendDetected: true,
|
||||
})
|
||||
);
|
||||
batch.then(() => {
|
||||
batch.commit();
|
||||
|
||||
// Initialize the backend only once the DevTools frontend Store has been initialized.
|
||||
// Otherwise the Store may miss important initial tree op codes.
|
||||
inject('dist/backend.js');
|
||||
});
|
||||
},
|
||||
|
||||
onReload(reloadFn) {
|
||||
|
|
|
@ -16,6 +16,8 @@ if (!TARGET) {
|
|||
|
||||
const __DEV__ = NODE_ENV === 'development';
|
||||
|
||||
const root = resolve(__dirname, '../..');
|
||||
|
||||
const GITHUB_URL = getGitHubURL();
|
||||
const DEVTOOLS_VERSION = getVersionString();
|
||||
|
||||
|
@ -24,12 +26,15 @@ const config = {
|
|||
devtool: false,
|
||||
entry: {
|
||||
app: './app/index.js',
|
||||
backend: './src/backend.js',
|
||||
devtools: './src/devtools.js',
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
src: resolve(__dirname, '../../src'),
|
||||
'react-devtools-inline': resolve(
|
||||
root,
|
||||
'packages/react-devtools-inline/src/'
|
||||
),
|
||||
src: resolve(root, 'src'),
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
|
@ -45,7 +50,7 @@ const config = {
|
|||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
configFile: require.resolve('../../babel.config.js'),
|
||||
configFile: resolve(root, 'babel.config.js'),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -153,20 +153,11 @@ export default class Overlay {
|
|||
|
||||
constructor() {
|
||||
// Find the root window, because overlays are positioned relative to it.
|
||||
let currentWindow = window;
|
||||
while (currentWindow !== currentWindow.parent) {
|
||||
currentWindow = currentWindow.parent;
|
||||
}
|
||||
let currentWindow = window.__REACT_DEVTOOLS_TARGET_WINDOW__ || window;
|
||||
this.window = currentWindow;
|
||||
|
||||
// When opened in shells/dev, the tooltip should be bound by the app iframe, not by the topmost window.
|
||||
let tipBoundsWindow = window;
|
||||
while (
|
||||
tipBoundsWindow !== tipBoundsWindow.parent &&
|
||||
!tipBoundsWindow.hasOwnProperty('__REACT_DEVTOOLS_GLOBAL_HOOK__')
|
||||
) {
|
||||
tipBoundsWindow = tipBoundsWindow.parent;
|
||||
}
|
||||
let tipBoundsWindow = window.__REACT_DEVTOOLS_TARGET_WINDOW__ || window;
|
||||
this.tipBoundsWindow = tipBoundsWindow;
|
||||
|
||||
const doc = currentWindow.document;
|
||||
|
|
|
@ -114,7 +114,7 @@ export default class Store extends EventEmitter<{|
|
|||
|
||||
// These options may be initially set by a confiugraiton option when constructing the Store.
|
||||
// In the case of "supportsProfiling", the option may be updated based on the injected renderers.
|
||||
_supportsNativeInspection: boolean = false;
|
||||
_supportsNativeInspection: boolean = true;
|
||||
_supportsProfiling: boolean = false;
|
||||
_supportsReloadAndProfile: boolean = false;
|
||||
|
||||
|
|
|
@ -59,7 +59,6 @@ export type Props = {|
|
|||
// but individual tabs (e.g. Components, Profiling) can be rendered into portals within their browser panels.
|
||||
componentsPortalContainer?: Element,
|
||||
profilerPortalContainer?: Element,
|
||||
settingsPortalContainer?: Element,
|
||||
|};
|
||||
|
||||
const componentsTab = {
|
||||
|
@ -85,7 +84,6 @@ export default function DevTools({
|
|||
componentsPortalContainer,
|
||||
overrideTab,
|
||||
profilerPortalContainer,
|
||||
settingsPortalContainer,
|
||||
showTabBar = false,
|
||||
showWelcomeToTheNewDevToolsDialog = false,
|
||||
store,
|
||||
|
@ -113,7 +111,6 @@ export default function DevTools({
|
|||
browserTheme={browserTheme}
|
||||
componentsPortalContainer={componentsPortalContainer}
|
||||
profilerPortalContainer={profilerPortalContainer}
|
||||
settingsPortalContainer={settingsPortalContainer}
|
||||
>
|
||||
<ViewElementSourceContext.Provider value={viewElementSource}>
|
||||
<TreeContextController>
|
||||
|
|
|
@ -41,7 +41,6 @@ type Props = {|
|
|||
children: React$Node,
|
||||
componentsPortalContainer?: Element,
|
||||
profilerPortalContainer?: Element,
|
||||
settingsPortalContainer?: Element,
|
||||
|};
|
||||
|
||||
function SettingsContextController({
|
||||
|
@ -49,7 +48,6 @@ function SettingsContextController({
|
|||
children,
|
||||
componentsPortalContainer,
|
||||
profilerPortalContainer,
|
||||
settingsPortalContainer,
|
||||
}: Props) {
|
||||
const bridge = useContext(BridgeContext);
|
||||
|
||||
|
@ -82,18 +80,8 @@ function SettingsContextController({
|
|||
.documentElement: any): HTMLElement)
|
||||
);
|
||||
}
|
||||
if (settingsPortalContainer != null) {
|
||||
array.push(
|
||||
((settingsPortalContainer.ownerDocument
|
||||
.documentElement: any): HTMLElement)
|
||||
);
|
||||
}
|
||||
return array;
|
||||
}, [
|
||||
componentsPortalContainer,
|
||||
profilerPortalContainer,
|
||||
settingsPortalContainer,
|
||||
]);
|
||||
}, [componentsPortalContainer, profilerPortalContainer]);
|
||||
|
||||
const computedStyle = getComputedStyle((document.body: any));
|
||||
const comfortableLineHeight = parseInt(
|
||||
|
|
Loading…
Reference in New Issue