mirror of
https://github.com/hanzoai/react.git
synced 2026-09-24 17:02:27 +00:00
> [!NOTE] > I had to invalidate `node_modules` cache keys on CI, because we are now using `react-devtools-facade` package and we need to create a symlink to it, otherwise Flow will fail. We use a hash value of `yarn.lock`, but it's not invalidated when a package inside yarn workspace is using another private package. --- This change introduces new `react-devtools-cdt-mcp` package, which is responsible for installing React tools for `chrome-devtools-mcp` server. It is using `react-devtools-facade` as a dependency: it doesn't own the implementation of these tools, it just relays Facade's tools to `chrome-devtools-mcp` format. When CDT MCP navigates to a fresh page, it emits unique `devtoolsdiscovery` method, that has `respondWith` method, which is the integration point between runtime libraries and MCP server. `react-devtools-cdt-mcp` is the owner for this integration. More details are available here - https://github.com/ChromeDevTools/chrome-devtools-mcp/blob/main/docs/third-party-developer-tools.md. Here is the list of tools that are being installed: - `react_get_component_tree` - `react_get_component_by_uid` - `react_find_components` - `react_get_component_source` - `react_get_owner_stack_trace` - `react_get_owner_stack` - `react_start_profiling` - `react_stop_profiling ` - `react_get_trace_overview` - `react_get_commit_report` --- Quick demo how to test the package with `chrome-devtools-mcp` CLI. Steps are also mentioned in `README` file: https://github.com/user-attachments/assets/af9fefce-03f0-4ebd-a94f-e9dd72b87f4d
118 lines
2.9 KiB
JavaScript
118 lines
2.9 KiB
JavaScript
import * as React from 'react';
|
|
|
|
const {
|
|
useState,
|
|
useEffect,
|
|
useCallback,
|
|
useContext,
|
|
createContext,
|
|
memo,
|
|
forwardRef,
|
|
} = React;
|
|
|
|
// A custom hook, to exercise the hooks tree in react_get_component_by_uid.
|
|
function useToggle(initial) {
|
|
const [on, setOn] = useState(initial);
|
|
const toggle = useCallback(() => setOn(value => !value), []);
|
|
return [on, toggle];
|
|
}
|
|
|
|
// Function component with a single State hook + a button that triggers
|
|
// re-renders (useful for profiling).
|
|
function Counter() {
|
|
const [count, setCount] = useState(0);
|
|
return (
|
|
<div className="row">
|
|
<span>Count: {count}</span>
|
|
<button onClick={() => setCount(value => value + 1)}>+1</button>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Uses the custom hook above, so its hooks tree nests a "Toggle" custom hook.
|
|
function Toggle() {
|
|
const [on, toggle] = useToggle(false);
|
|
return <button onClick={toggle}>{on ? 'ON' : 'OFF'}</button>;
|
|
}
|
|
|
|
// State + Effect hook with a timer — re-renders every second, handy for
|
|
// react_start_profiling / react_get_trace_overview / react_get_commit_report.
|
|
function Clock() {
|
|
const [now, setNow] = useState(() => new Date().toLocaleTimeString());
|
|
useEffect(() => {
|
|
const id = setInterval(() => setNow(new Date().toLocaleTimeString()), 1000);
|
|
return () => clearInterval(id);
|
|
}, []);
|
|
return <div className="row">Clock: {now}</div>;
|
|
}
|
|
|
|
// Context, to exercise the "context" node type and useContext.
|
|
const ThemeContext = createContext('light');
|
|
|
|
function ThemeProvider({children}) {
|
|
return <ThemeContext.Provider value="dark">{children}</ThemeContext.Provider>;
|
|
}
|
|
|
|
function ThemedPanel() {
|
|
const theme = useContext(ThemeContext);
|
|
return (
|
|
<section className="panel" data-theme={theme}>
|
|
<h2>Panel (theme: {theme})</h2>
|
|
<Counter />
|
|
<Toggle />
|
|
<Clock />
|
|
</section>
|
|
);
|
|
}
|
|
|
|
// List with keys, to exercise key reporting and find_components pagination.
|
|
function Todo({text}) {
|
|
return <li>{text}</li>;
|
|
}
|
|
|
|
function TodoList() {
|
|
const items = [
|
|
{id: 'learn', text: 'Learn the tools'},
|
|
{id: 'test', text: 'Test the fixture'},
|
|
{id: 'ship', text: 'Ship the package'},
|
|
];
|
|
return (
|
|
<ul className="todos">
|
|
{items.map(item => (
|
|
<Todo key={item.id} text={item.text} />
|
|
))}
|
|
</ul>
|
|
);
|
|
}
|
|
|
|
// memo and forwardRef, to exercise the "memo" and "forwardRef" node types.
|
|
const MemoBox = memo(function MemoBox({label}) {
|
|
return <div className="box">Memo: {label}</div>;
|
|
});
|
|
|
|
const FancyInput = forwardRef(function FancyInput({placeholder}, ref) {
|
|
return <input ref={ref} placeholder={placeholder} />;
|
|
});
|
|
|
|
function Header() {
|
|
return (
|
|
<header>
|
|
<h1>react-devtools-cdt-mcp fixture</h1>
|
|
</header>
|
|
);
|
|
}
|
|
|
|
export default function App() {
|
|
return (
|
|
<main className="app">
|
|
<Header />
|
|
<ThemeProvider>
|
|
<ThemedPanel />
|
|
</ThemeProvider>
|
|
<TodoList />
|
|
<MemoBox label="hello" />
|
|
<FancyInput placeholder="type here" />
|
|
</main>
|
|
);
|
|
}
|