diff --git a/src/backend/renderer.js b/src/backend/renderer.js index cccc27779a..3c5729c73f 100644 --- a/src/backend/renderer.js +++ b/src/backend/renderer.js @@ -639,12 +639,15 @@ export function attach( idToTreeBaseDurationMap.set(id, fiber.treeBaseDuration); } + const hasOwnerMetadata = fiber.hasOwnProperty('_debugOwner'); + if (isRoot) { - const operation = new Uint32Array(4); + const operation = new Uint32Array(5); operation[0] = TREE_OPERATION_ADD; operation[1] = id; operation[2] = ElementTypeRoot; operation[3] = isProfilingSupported ? 1 : 0; + operation[4] = hasOwnerMetadata ? 1 : 0; addOperation(operation); } else { const { displayName, key, type } = getDataForFiber(fiber); diff --git a/src/bridge.js b/src/bridge.js index 9b3c3dd318..3eed1efb16 100644 --- a/src/bridge.js +++ b/src/bridge.js @@ -51,7 +51,7 @@ export default class Bridge extends EventEmitter { this._wall.send( this._messageQueue[i], this._messageQueue[i + 1], - this._messageQueue[i + 2], + this._messageQueue[i + 2] ); } this._messageQueue.length = 0; diff --git a/src/devtools/store.js b/src/devtools/store.js index d81b6e89c1..4a829938d5 100644 --- a/src/devtools/store.js +++ b/src/devtools/store.js @@ -48,6 +48,7 @@ type Config = {| |}; export type Capabilities = {| + hasOwnerMetadata: boolean, supportsProfiling: boolean, |}; @@ -60,6 +61,9 @@ export default class Store extends EventEmitter { _captureScreenshots: boolean = false; + // At least one of the injected renderers contains (DEV only) owner metadata. + _hasOwnerMetadata: boolean = false; + // Map of ID to Element. // Elements are mutable (for now) to avoid excessive cloning during tree updates. _idToElement: Map = new Map(); @@ -174,6 +178,10 @@ export default class Store extends EventEmitter { this.emit('captureScreenshots'); } + get hasOwnerMetadata(): boolean { + return this._hasOwnerMetadata; + } + // Profiling data has been recorded for at least one root. get hasProfilingData(): boolean { return ( @@ -534,9 +542,15 @@ export default class Store extends EventEmitter { const supportsProfiling = operations[i] > 0; i++; + const hasOwnerMetadata = operations[i] > 0; + i++; + this._roots = this._roots.concat(id); this._rootIDToRendererID.set(id, rendererID); - this._rootIDToCapabilities.set(id, { supportsProfiling }); + this._rootIDToCapabilities.set(id, { + hasOwnerMetadata, + supportsProfiling, + }); this._idToElement.set(id, { children: [], @@ -768,12 +782,18 @@ export default class Store extends EventEmitter { this._revision++; if (haveRootsChanged) { + this._hasOwnerMetadata = false; this._supportsProfiling = false; - this._rootIDToCapabilities.forEach(({ supportsProfiling }) => { - if (supportsProfiling) { - this._supportsProfiling = true; + this._rootIDToCapabilities.forEach( + ({ hasOwnerMetadata, supportsProfiling }) => { + if (hasOwnerMetadata) { + this._hasOwnerMetadata = true; + } + if (supportsProfiling) { + this._supportsProfiling = true; + } } - }); + ); this.emit('roots'); } diff --git a/src/devtools/views/Components/TreeContext.js b/src/devtools/views/Components/TreeContext.js index d610cddfb3..4594c7dfa0 100644 --- a/src/devtools/views/Components/TreeContext.js +++ b/src/devtools/views/Components/TreeContext.js @@ -484,30 +484,34 @@ function reduceOwnersState(store: Store, state: State, action: Action): State { } break; case 'SELECT_OWNER': - ownerStackIndex = ownerStack.indexOf(payload); + // If the Store doesn't have any owners metadata, don't drill into an empty stack. + // This is a confusing user experience. + if (store.hasOwnerMetadata) { + ownerStackIndex = ownerStack.indexOf(payload); - // Always force reset selection to be the top of the new owner tree. - selectedElementIndex = 0; - prevSelectedElementIndex = null; + // Always force reset selection to be the top of the new owner tree. + selectedElementIndex = 0; + prevSelectedElementIndex = null; - // If this owner is already in the current stack, just select it. - // Otherwise, create a new stack. - if (ownerStackIndex < 0) { - // Add this new owner, and fill in the owners above it as well. - ownerStack = []; - let currentOwnerID = ((payload: any): number); - while (currentOwnerID !== 0) { - ownerStack.unshift(currentOwnerID); - currentOwnerID = ((store.getElementByID( - currentOwnerID - ): any): Element).ownerID; - } - ownerStackIndex = ownerStack.length - 1; + // If this owner is already in the current stack, just select it. + // Otherwise, create a new stack. + if (ownerStackIndex < 0) { + // Add this new owner, and fill in the owners above it as well. + ownerStack = []; + let currentOwnerID = ((payload: any): number); + while (currentOwnerID !== 0) { + ownerStack.unshift(currentOwnerID); + currentOwnerID = ((store.getElementByID( + currentOwnerID + ): any): Element).ownerID; + } + ownerStackIndex = ownerStack.length - 1; - if (searchText !== '') { - searchIndex = null; - searchResults = []; - searchText = ''; + if (searchText !== '') { + searchIndex = null; + searchResults = []; + searchText = ''; + } } } break; diff --git a/src/devtools/views/Profiler/CommitTreeBuilder.js b/src/devtools/views/Profiler/CommitTreeBuilder.js index 39fa6c131c..2629fbeedb 100644 --- a/src/devtools/views/Profiler/CommitTreeBuilder.js +++ b/src/devtools/views/Profiler/CommitTreeBuilder.js @@ -194,6 +194,7 @@ function updateTree( if (type === ElementTypeRoot) { i++; // supportsProfiling flag + i++; // hasOwnerMetadata flag if (__DEBUG__) { debug('Add', `new root fiber ${id}`);