Skip to content

Commit 96c5846

Browse files
authored
feat[devtools]: add package for fusebox integration (#28553)
## Summary Stacked on #28552. Review only the [last commit at the top](c69952f). These changes add new package `react-devtools-fusebox`, which is the entrypoint for the RDT Frontend, which will be used in Chrome DevTools panel. The main differences from other frontend shells (extension, standalone) are: 1. This package builds scripts in ESM format, this is required by Chrome DevTools, see webpack config: https://github.com/facebook/react/blob/c69952f1bf6e23252d47e0f7eb98efbbb2cc2c55/packages/react-devtools-fusebox/webpack.config.frontend.js#L50-L52 2. The build includes styles in a separate `.css` file, which is required for Chrome DevTools: styles are loaded lazily once panel is mounted.
1 parent d012a32 commit 96c5846

File tree

7 files changed

+337
-3
lines changed

7 files changed

+337
-3
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ packages/react-devtools-extensions/firefox/*.xpi
3333
packages/react-devtools-extensions/firefox/*.pem
3434
packages/react-devtools-extensions/shared/build
3535
packages/react-devtools-extensions/.tempUserDataDir
36+
packages/react-devtools-fusebox/dist
3637
packages/react-devtools-inline/dist
3738
packages/react-devtools-shell/dist
3839
packages/react-devtools-timeline/dist
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# react-native-fusebox
2+
3+
This package is private and not expected to become public anytime soon. Consider using [react-devtools-inline](https://github.com/facebook/react/tree/main/packages/react-devtools-inline) or [react-devtools-core](https://github.com/facebook/react/tree/main/packages/react-devtools-core).
4+
5+
## What is Fusebox?
6+
"Fusebox" is the internal codename for the new React Native debugger stack based on Chrome DevTools.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "react-devtools-fusebox",
3+
"version": "0.0.0",
4+
"private": "true",
5+
"license": "MIT",
6+
"files": ["dist"],
7+
"scripts": {
8+
"build:frontend:local": "cross-env NODE_ENV=development webpack --config webpack.config.frontend.js",
9+
"build:frontend": "cross-env NODE_ENV=production webpack --config webpack.config.frontend.js",
10+
"build": "yarn build:frontend"
11+
},
12+
"devDependencies": {
13+
"buffer": "^6.0.3",
14+
"cross-env": "^7.0.3",
15+
"css-loader": "^6.9.1",
16+
"mini-css-extract-plugin": "^2.7.7",
17+
"process": "^0.11.10",
18+
"webpack": "^5.82.1",
19+
"webpack-cli": "^5.1.1",
20+
"workerize-loader": "^2.0.2"
21+
}
22+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow
8+
*/
9+
10+
import * as React from 'react';
11+
import {createRoot} from 'react-dom/client';
12+
import Bridge from 'react-devtools-shared/src/bridge';
13+
import Store from 'react-devtools-shared/src/devtools/store';
14+
import DevTools from 'react-devtools-shared/src/devtools/views/DevTools';
15+
16+
import type {Wall} from 'react-devtools-shared/src/frontend/types';
17+
import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
18+
19+
type Config = {
20+
checkBridgeProtocolCompatibility?: boolean,
21+
supportsNativeInspection?: boolean,
22+
supportsProfiling?: boolean,
23+
};
24+
25+
export function createBridge(wall?: Wall): FrontendBridge {
26+
if (wall != null) {
27+
return new Bridge(wall);
28+
}
29+
30+
return new Bridge({listen: () => {}, send: () => {}});
31+
}
32+
33+
export function createStore(bridge: FrontendBridge, config?: Config): Store {
34+
return new Store(bridge, {
35+
checkBridgeProtocolCompatibility: true,
36+
supportsTraceUpdates: true,
37+
supportsNativeInspection: true,
38+
...config,
39+
});
40+
}
41+
42+
type InitializationOptions = {
43+
bridge: FrontendBridge,
44+
store: Store,
45+
};
46+
47+
export function initialize(
48+
contentWindow: Element | Document,
49+
options: InitializationOptions,
50+
): void {
51+
const {bridge, store} = options;
52+
const root = createRoot(contentWindow);
53+
54+
root.render(
55+
<DevTools
56+
bridge={bridge}
57+
store={store}
58+
showTabBar={true}
59+
warnIfLegacyBackendDetected={true}
60+
/>,
61+
);
62+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
const {resolve} = require('path');
2+
const Webpack = require('webpack');
3+
const {
4+
DARK_MODE_DIMMED_WARNING_COLOR,
5+
DARK_MODE_DIMMED_ERROR_COLOR,
6+
DARK_MODE_DIMMED_LOG_COLOR,
7+
LIGHT_MODE_DIMMED_WARNING_COLOR,
8+
LIGHT_MODE_DIMMED_ERROR_COLOR,
9+
LIGHT_MODE_DIMMED_LOG_COLOR,
10+
GITHUB_URL,
11+
getVersionString,
12+
} = require('react-devtools-extensions/utils');
13+
const {resolveFeatureFlags} = require('react-devtools-shared/buildUtils');
14+
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
15+
16+
const NODE_ENV = process.env.NODE_ENV;
17+
if (!NODE_ENV) {
18+
console.error('NODE_ENV not set');
19+
process.exit(1);
20+
}
21+
22+
const builtModulesDir = resolve(
23+
__dirname,
24+
'..',
25+
'..',
26+
'build',
27+
'oss-experimental',
28+
);
29+
30+
const __DEV__ = NODE_ENV === 'development';
31+
32+
const EDITOR_URL = process.env.EDITOR_URL || null;
33+
34+
const DEVTOOLS_VERSION = getVersionString();
35+
36+
const babelOptions = {
37+
configFile: resolve(
38+
__dirname,
39+
'..',
40+
'react-devtools-shared',
41+
'babel.config.js',
42+
),
43+
};
44+
45+
module.exports = {
46+
mode: __DEV__ ? 'development' : 'production',
47+
entry: {
48+
frontend: './src/frontend.js',
49+
},
50+
experiments: {
51+
outputModule: true,
52+
},
53+
output: {
54+
path: __dirname + '/dist',
55+
publicPath: '/dist/',
56+
filename: '[name].js',
57+
chunkFilename: '[name].chunk.js',
58+
library: {
59+
type: 'module',
60+
},
61+
},
62+
node: {
63+
global: false,
64+
},
65+
resolve: {
66+
alias: {
67+
'react-devtools-feature-flags': resolveFeatureFlags('fusebox'),
68+
react: resolve(builtModulesDir, 'react'),
69+
'react-debug-tools': resolve(builtModulesDir, 'react-debug-tools'),
70+
'react-dom/client': resolve(builtModulesDir, 'react-dom/client'),
71+
'react-dom': resolve(builtModulesDir, 'react-dom'),
72+
'react-is': resolve(builtModulesDir, 'react-is'),
73+
scheduler: resolve(builtModulesDir, 'scheduler'),
74+
},
75+
},
76+
optimization: {
77+
minimize: false,
78+
},
79+
plugins: [
80+
new MiniCssExtractPlugin(),
81+
new Webpack.ProvidePlugin({
82+
process: 'process/browser',
83+
Buffer: ['buffer', 'Buffer'],
84+
}),
85+
new Webpack.DefinePlugin({
86+
__DEV__,
87+
__EXPERIMENTAL__: true,
88+
__EXTENSION__: false,
89+
__PROFILE__: false,
90+
__TEST__: NODE_ENV === 'test',
91+
'process.env.DEVTOOLS_PACKAGE': `"react-devtools-fusebox"`,
92+
'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`,
93+
'process.env.EDITOR_URL': EDITOR_URL != null ? `"${EDITOR_URL}"` : null,
94+
'process.env.GITHUB_URL': `"${GITHUB_URL}"`,
95+
'process.env.NODE_ENV': `"${NODE_ENV}"`,
96+
'process.env.DARK_MODE_DIMMED_WARNING_COLOR': `"${DARK_MODE_DIMMED_WARNING_COLOR}"`,
97+
'process.env.DARK_MODE_DIMMED_ERROR_COLOR': `"${DARK_MODE_DIMMED_ERROR_COLOR}"`,
98+
'process.env.DARK_MODE_DIMMED_LOG_COLOR': `"${DARK_MODE_DIMMED_LOG_COLOR}"`,
99+
'process.env.LIGHT_MODE_DIMMED_WARNING_COLOR': `"${LIGHT_MODE_DIMMED_WARNING_COLOR}"`,
100+
'process.env.LIGHT_MODE_DIMMED_ERROR_COLOR': `"${LIGHT_MODE_DIMMED_ERROR_COLOR}"`,
101+
'process.env.LIGHT_MODE_DIMMED_LOG_COLOR': `"${LIGHT_MODE_DIMMED_LOG_COLOR}"`,
102+
}),
103+
],
104+
module: {
105+
rules: [
106+
{
107+
test: /\.worker\.js$/,
108+
use: [
109+
{
110+
loader: 'workerize-loader',
111+
options: {
112+
inline: true,
113+
name: '[name]',
114+
},
115+
},
116+
{
117+
loader: 'babel-loader',
118+
options: babelOptions,
119+
},
120+
],
121+
},
122+
{
123+
test: /\.js$/,
124+
loader: 'babel-loader',
125+
options: babelOptions,
126+
},
127+
{
128+
test: /\.css$/i,
129+
use: [
130+
{
131+
loader: MiniCssExtractPlugin.loader,
132+
},
133+
{
134+
loader: 'css-loader',
135+
options: {modules: true},
136+
},
137+
],
138+
},
139+
],
140+
},
141+
};

packages/react-devtools-shared/buildUtils.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ function resolveFeatureFlags(target) {
1313
switch (target) {
1414
case 'inline':
1515
case 'shell':
16+
case 'fusebox':
1617
flagsPath = 'DevToolsFeatureFlags.default';
1718
break;
1819
case 'core/backend-oss':

0 commit comments

Comments
 (0)