React Native: Standalone package and basic RN support
bvaughn opened this issue · 3 comments
Need to create react-devtools
and react-devtools-core
packages to support React Native, Safari, iframes, and other embedded cases like Nuclide and Flipper.
- Test standalone shell with Safari
- Test standalone shell with iOS React Native (with and without v8)
- Test standalone shell with Android React Native
- Test embedded integration with Flipper
Some features will require changes to support the RN environment:
- Component filters will need to be saved somewhere between reloads. (Perhaps they will need to be sent eagerly on connect, similar to how we do for reload-and-profile in the browser.)
- Inspecting an element in React Native should also select it in DevTools.
-
The selection tool in DevTools should enable clicking on a native view in React Native to select its owner. - Overlay/highlight component to show the currently-selected component. (Currently this is just disabled for RN.)
-
Determine if it would be possible to support reload-and-profile functionality for React Native. -
Don't hide the DevTools app if Profiler has data when an app unmounts. - React Native style editor plug-in. (Maybe we can use view config as a whitelist of all valid prop names?)
-
Fabric support (stretch goal) -
Special tag/badge for native components (React Native will be dropping the "RCT" prefix soon). - Inspect component in IDE (launch editor) feature.
In addition, because the v4 backend API is incompatible with v3, releasing the new react-devtools
and react-devtools-core
packages will also require updating and coordinating with: React Native, Flipper, and Nuclide packages (and possibly others).
For now, I will be pushing my work to the npm-packages
branch. I will rebase and cleanup before merging.
Hi @bvaughn, do you have any work about the update for Inspector.js? Currently it isn't working with the global hook of v4.
@jhen0409 Yes, I have a patch to a few React Native components. Inspector
and several of the YellowBox
* components. Here's the Inspector
patch 😄
33c33,34
< // required for devtools to be able to edit react native styles
---
> // Required for React DevTools to view/edit React Native styles in Flipper.
> // Flipper doesn't inject these values when initializing DevTools.
34a36,39
> const viewConfig = require('../Components/View/ReactNativeViewViewConfig.js');
> hook.nativeStyleEditorValidAttributes = Object.keys(
> viewConfig.validAttributes.style,
> );
37,39c42
< const allRenderers = Object.keys(hook._renderers).map(
< key => hook._renderers[key],
< );
---
> const allRenderers = Array.from(hook.renderers.values());
80a84
> _hideTimeoutID: TimeoutID | null = null;
119,126c123,125
< let _hideWait = null;
< const hlSub = agent.sub('highlight', ({node, name, props}) => {
< clearTimeout(_hideWait);
<
< if (typeof node !== 'number') {
< // Fiber
< node = ReactNative.findNodeHandle(node);
< }
---
> agent.addListener('hideNativeHighlight', this._onAgentHideNativeHighlight);
> agent.addListener('showNativeHighlight', this._onAgentShowNativeHighlight);
> agent.addListener('shutdown', this._onAgentShutdown);
128,136c127,128
< UIManager.measure(node, (x, y, width, height, left, top) => {
< this.setState({
< hierarchy: [],
< inspected: {
< frame: {left, top, width, height},
< style: props ? props.style : {},
< },
< });
< });
---
> this.setState({
> devtoolsAgent: agent,
138,147c130,157
< const hideSub = agent.sub('hideHighlight', () => {
< if (this.state.inspected === null) {
< return;
< }
< // we wait to actually hide in order to avoid flicker
< _hideWait = setTimeout(() => {
< this.setState({
< inspected: null,
< });
< }, 100);
---
> };
>
> _onAgentHideNativeHighlight = () => {
> if (this.state.inspected === null) {
> return;
> }
> // we wait to actually hide in order to avoid flicker
> this._hideTimeoutID = setTimeout(() => {
> this.setState({
> inspected: null,
> });
> }, 100);
> };
>
> _onAgentShowNativeHighlight = node => {
> clearTimeout(this._hideTimeoutID);
>
> if (typeof node !== 'number') {
> node = ReactNative.findNodeHandle(node);
> }
>
> UIManager.measure(node, (x, y, width, height, left, top) => {
> this.setState({
> hierarchy: [],
> inspected: {
> frame: {left, top, width, height},
> },
> });
149c159,172
< this._subs = [hlSub, hideSub];
---
> };
>
> _onAgentShutdown = () => {
> const agent = this.state.devtoolsAgent;
> if (agent != null) {
> agent.removeListener(
> 'hideNativeHighlight',
> this._onAgentHideNativeHighlight,
> );
> agent.removeListener(
> 'showNativeHighlight',
> this._onAgentShowNativeHighlight,
> );
> agent.removeListener('shutdown', this._onAgentShutdown);
151d173
< agent.on('shutdown', () => {
153,157c175
< this._subs = null;
< });
< this.setState({
< devtoolsAgent: agent,
< });
---
> }
190,194c208
< this.state.devtoolsAgent.selectFromDOMNode(
< touchedViewTag,
< true,
< offsetFromLeaf,
< );
---
> this.state.devtoolsAgent.selectNode(touchedViewTag);
I will be landing support for this today (hopefully) within Facebook. Going to close this out for now.