-
Notifications
You must be signed in to change notification settings - Fork 51k
Adds a ReactNativeInspector API to ReactNativeRenderer #9691
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
Merged
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
ddfd05f
fixed conflicts with master
trueadm 12e8367
splits fiber and stack implementations
trueadm 9cb93e5
prettier run
trueadm 87d5fa3
Merge remote-tracking branch 'upstream/master' into reactnativeinspec…
trueadm 179926e
updated fiber implementation based on feedback
trueadm 6edea82
updated fiber implementation for selecting inspector hierarchy
trueadm 416c207
run of prettier
trueadm 532912a
fixed flow issues
trueadm 159efdb
updated stack implementation
trueadm 3a3d8c3
fixes an implementation difference where before it wasnt properly und…
trueadm ba9c3fa
addresses comments in PR feedback
trueadm 28bef25
updated stack inspector to use emptyObject
trueadm 0f88fa5
Update ReactNativeFiberInspector.js
trueadm 450da60
fixes last flow error
trueadm 6215bf9
prettier
trueadm d378e9c
applied changes to how viewConfig works for fibers and extracted meas…
trueadm 76b721a
fixed bad paste
trueadm 4ce3fc8
fixes flow errors
trueadm fc0c137
prettyify
trueadm a6f8e6b
revmoed getComponentName changes
trueadm 3e84ec9
updated logic for getHostProps and addressed other PR feedback
trueadm e0e443e
improved throwing to invariant and update stack implemenation based o…
trueadm b05ef94
prettier
trueadm File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,124 @@ | ||
| /** | ||
| * Copyright (c) 2015-present, Facebook, Inc. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under the BSD-style license found in the | ||
| * LICENSE file in the root directory of this source tree. An additional grant | ||
| * of patent rights can be found in the PATENTS file in the same directory. | ||
| * | ||
| * @providesModule ReactNativeFiberInspector | ||
| * @flow | ||
| */ | ||
| 'use strict'; | ||
|
|
||
| const ReactNativeComponentTree = require('ReactNativeComponentTree'); | ||
| const ReactFiberTreeReflection = require('ReactFiberTreeReflection'); | ||
| const getComponentName = require('getComponentName'); | ||
| const emptyObject = require('fbjs/lib/emptyObject'); | ||
| const ReactTypeOfWork = require('ReactTypeOfWork'); | ||
| const UIManager = require('UIManager'); | ||
| const invariant = require('fbjs/lib/invariant'); | ||
|
|
||
| const {getClosestInstanceFromNode} = ReactNativeComponentTree; | ||
| const {findCurrentFiberUsingSlowPath} = ReactFiberTreeReflection; | ||
| const {HostComponent} = ReactTypeOfWork; | ||
|
|
||
| import type {Fiber} from 'ReactFiber'; | ||
|
|
||
| let getInspectorDataForViewTag; | ||
|
|
||
| if (__DEV__) { | ||
| var traverseOwnerTreeUp = function(hierarchy, instance: any) { | ||
| if (instance) { | ||
| hierarchy.unshift(instance); | ||
| traverseOwnerTreeUp(hierarchy, instance._debugOwner); | ||
| } | ||
| }; | ||
|
|
||
| var getOwnerHierarchy = function(instance: any) { | ||
| var hierarchy = []; | ||
| traverseOwnerTreeUp(hierarchy, instance); | ||
| return hierarchy; | ||
| }; | ||
|
|
||
| var lastNonHostInstance = function(hierarchy) { | ||
| for (let i = hierarchy.length - 1; i > 1; i--) { | ||
| const instance = hierarchy[i]; | ||
|
|
||
| if (instance.tag !== HostComponent) { | ||
| return instance; | ||
| } | ||
| } | ||
| return hierarchy[0]; | ||
| }; | ||
|
|
||
| var getHostProps = function(fiber) { | ||
| const host = ReactFiberTreeReflection.findCurrentHostFiber(fiber); | ||
| if (host) { | ||
| return host.memoizedProps || emptyObject; | ||
| } | ||
| return emptyObject; | ||
| }; | ||
|
|
||
| var getHostNode = function(fiber: Fiber | null, findNodeHandle) { | ||
| let hostNode; | ||
| // look for children first for the hostNode | ||
| // as composite fibers do not have a hostNode | ||
| while (fiber) { | ||
| if (fiber.stateNode !== null && fiber.tag === HostComponent) { | ||
| hostNode = findNodeHandle(fiber.stateNode); | ||
| } | ||
| if (hostNode) { | ||
| return hostNode; | ||
| } | ||
| fiber = fiber.child; | ||
| } | ||
| return null; | ||
| }; | ||
|
|
||
| var stripTopSecret = str => | ||
| typeof str === 'string' && str.replace('topsecret-', ''); | ||
|
|
||
| var createHierarchy = function(fiberHierarchy) { | ||
| return fiberHierarchy.map(fiber => ({ | ||
| name: stripTopSecret(getComponentName(fiber)), | ||
| getInspectorData: findNodeHandle => ({ | ||
| measure: callback => | ||
| UIManager.measure(getHostNode(fiber, findNodeHandle), callback), | ||
| props: getHostProps(fiber), | ||
| source: fiber._debugSource, | ||
| }), | ||
| })); | ||
| }; | ||
|
|
||
| getInspectorDataForViewTag = function(viewTag: number): Object { | ||
| const fiber = findCurrentFiberUsingSlowPath( | ||
| getClosestInstanceFromNode(viewTag), | ||
| ); | ||
| const fiberHierarchy = getOwnerHierarchy(fiber); | ||
| const instance = lastNonHostInstance(fiberHierarchy); | ||
| const hierarchy = createHierarchy(fiberHierarchy); | ||
| const props = getHostProps(instance); | ||
| const source = instance._debugSource; | ||
| const selection = fiberHierarchy.indexOf(instance); | ||
|
|
||
| return { | ||
| hierarchy, | ||
| instance, | ||
| props, | ||
| selection, | ||
| source, | ||
| }; | ||
| }; | ||
| } else { | ||
| getInspectorDataForViewTag = () => { | ||
| invariant( | ||
| false, | ||
| 'getInspectorDataForViewTag() is not available in production', | ||
| ); | ||
| }; | ||
| } | ||
|
|
||
| module.exports = { | ||
| getInspectorDataForViewTag, | ||
| }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| /** | ||
| * Copyright (c) 2015-present, Facebook, Inc. | ||
| * All rights reserved. | ||
| * | ||
| * This source code is licensed under the BSD-style license found in the | ||
| * LICENSE file in the root directory of this source tree. An additional grant | ||
| * of patent rights can be found in the PATENTS file in the same directory. | ||
| * | ||
| * @providesModule ReactNativeStackInspector | ||
| * @flow | ||
| */ | ||
| 'use strict'; | ||
|
|
||
| const ReactNativeComponentTree = require('ReactNativeComponentTree'); | ||
| const getComponentName = require('getComponentName'); | ||
| const emptyObject = require('fbjs/lib/emptyObject'); | ||
| const UIManager = require('UIManager'); | ||
| const invariant = require('fbjs/lib/invariant'); | ||
|
|
||
| let getInspectorDataForViewTag; | ||
|
|
||
| if (__DEV__) { | ||
| var traverseOwnerTreeUp = function(hierarchy, instance) { | ||
| if (instance) { | ||
| hierarchy.unshift(instance); | ||
| traverseOwnerTreeUp(hierarchy, instance._currentElement._owner); | ||
| } | ||
| }; | ||
|
|
||
| var getOwnerHierarchy = function(instance) { | ||
| var hierarchy = []; | ||
| traverseOwnerTreeUp(hierarchy, instance); | ||
| return hierarchy; | ||
| }; | ||
|
|
||
| var lastNotNativeInstance = function(hierarchy) { | ||
| for (let i = hierarchy.length - 1; i > 1; i--) { | ||
| const instance = hierarchy[i]; | ||
| if (!instance.viewConfig) { | ||
| return instance; | ||
| } | ||
| } | ||
| return hierarchy[0]; | ||
| }; | ||
|
|
||
| var getHostProps = function(component) { | ||
| const instance = component._instance; | ||
| if (instance) { | ||
| return instance.props || emptyObject; | ||
| } | ||
| return emptyObject; | ||
| }; | ||
|
|
||
| var createHierarchy = function(componentHierarchy) { | ||
| return componentHierarchy.map(component => ({ | ||
| name: getComponentName(component), | ||
| getInspectorData: () => ({ | ||
| measure: callback => | ||
| UIManager.measure(component.getHostNode(), callback), | ||
| props: getHostProps(component), | ||
| source: component._currentElement && component._currentElement._source, | ||
| }), | ||
| })); | ||
| }; | ||
|
|
||
| getInspectorDataForViewTag = function(viewTag: any): Object { | ||
| const component = ReactNativeComponentTree.getClosestInstanceFromNode( | ||
| viewTag, | ||
| ); | ||
| const componentHierarchy = getOwnerHierarchy(component); | ||
| const instance = lastNotNativeInstance(componentHierarchy); | ||
| const hierarchy = createHierarchy(componentHierarchy); | ||
| const props = getHostProps(instance); | ||
| const source = instance._currentElement && instance._currentElement._source; | ||
| const selection = componentHierarchy.indexOf(instance); | ||
|
|
||
| return { | ||
| hierarchy, | ||
| instance, | ||
| props, | ||
| selection, | ||
| source, | ||
| }; | ||
| }; | ||
| } else { | ||
| getInspectorDataForViewTag = () => { | ||
| invariant( | ||
| false, | ||
| 'getInspectorDataForViewTag() is not available in production', | ||
| ); | ||
| }; | ||
| } | ||
|
|
||
| module.exports = { | ||
| getInspectorDataForViewTag, | ||
| }; |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the value added by this UI is that you can inspect a quick breadcrumb - on the device. Otherwise you can just use the full DevTools.
There's nothing inherently ReactNative specific about this type of UI. Mobile web could use the same. We should build the same thing for web if it is useful to have a UI that just quickly shows the breadcrumb.
As a start, can we move this to "shared" and call it something more generic like ReactFiberBreadCrumbInspector.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this something that is going to add a lot of value to do now rather than later? I get the reasoning for doing this, but I feel having a working Fiber inspector merged soon along with RN flat bundles is going to be of more value. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree I’d prefer we do another pass at this later, but unblock RN Fiber rollout now.
(After fixing the other issues where we seem very close)