Skip to content
Merged
Show file tree
Hide file tree
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 May 15, 2017
12e8367
splits fiber and stack implementations
trueadm May 15, 2017
9cb93e5
prettier run
trueadm May 15, 2017
87d5fa3
Merge remote-tracking branch 'upstream/master' into reactnativeinspec…
trueadm May 15, 2017
179926e
updated fiber implementation based on feedback
trueadm May 16, 2017
6edea82
updated fiber implementation for selecting inspector hierarchy
trueadm May 16, 2017
416c207
run of prettier
trueadm May 22, 2017
532912a
fixed flow issues
trueadm May 22, 2017
159efdb
updated stack implementation
trueadm May 22, 2017
3a3d8c3
fixes an implementation difference where before it wasnt properly und…
trueadm May 22, 2017
ba9c3fa
addresses comments in PR feedback
trueadm May 23, 2017
28bef25
updated stack inspector to use emptyObject
trueadm May 23, 2017
0f88fa5
Update ReactNativeFiberInspector.js
trueadm May 23, 2017
450da60
fixes last flow error
trueadm May 23, 2017
6215bf9
prettier
trueadm May 23, 2017
d378e9c
applied changes to how viewConfig works for fibers and extracted meas…
trueadm May 23, 2017
76b721a
fixed bad paste
trueadm May 23, 2017
4ce3fc8
fixes flow errors
trueadm May 23, 2017
fc0c137
prettyify
trueadm May 23, 2017
a6f8e6b
revmoed getComponentName changes
trueadm May 23, 2017
3e84ec9
updated logic for getHostProps and addressed other PR feedback
trueadm May 23, 2017
e0e443e
improved throwing to invariant and update stack implemenation based o…
trueadm May 23, 2017
b05ef94
prettier
trueadm May 23, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/renderers/native/ReactNativeFiber.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const ReactNativeInjection = require('ReactNativeInjection');
const ReactNativeTagHandles = require('ReactNativeTagHandles');
const ReactNativeViewConfigRegistry = require('ReactNativeViewConfigRegistry');
const ReactPortal = require('ReactPortal');
const ReactNativeFiberInspector = require('ReactNativeFiberInspector');
const ReactVersion = require('ReactVersion');
const UIManager = require('UIManager');

Expand Down Expand Up @@ -465,6 +466,7 @@ if (typeof injectInternals === 'function') {
injectInternals({
findFiberByHostInstance: ReactNativeComponentTree.getClosestInstanceFromNode,
findHostInstanceByFiber: NativeRenderer.findHostInstance,
getInspectorDataForViewTag: ReactNativeFiberInspector.getInspectorDataForViewTag,
// This is an enum because we may add more (e.g. profiler build)
bundleType: __DEV__ ? 1 : 0,
version: ReactVersion,
Expand Down
124 changes: 124 additions & 0 deletions src/renderers/native/ReactNativeFiberInspector.js
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
Copy link
Copy Markdown
Contributor

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.

Copy link
Copy Markdown
Contributor Author

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?

Copy link
Copy Markdown
Collaborator

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)

* @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,
};
2 changes: 2 additions & 0 deletions src/renderers/native/ReactNativeStack.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ var ReactNativeInjection = require('ReactNativeInjection');
var ReactNativeMount = require('ReactNativeMount');
var ReactNativeStackInjection = require('ReactNativeStackInjection');
var ReactUpdates = require('ReactUpdates');
var ReactNativeStackInspector = require('ReactNativeStackInspector');

var findNodeHandle = require('findNodeHandle');

Expand Down Expand Up @@ -81,6 +82,7 @@ if (
},
Mount: ReactNativeMount,
Reconciler: require('ReactReconciler'),
getInspectorDataForViewTag: ReactNativeStackInspector.getInspectorDataForViewTag,
});
}

Expand Down
96 changes: 96 additions & 0 deletions src/renderers/native/ReactNativeStackInspector.js
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,
};