diff --git a/src/backend/index.js b/src/backend/index.js index efa6e83489..298d06a121 100644 --- a/src/backend/index.js +++ b/src/backend/index.js @@ -23,7 +23,10 @@ export function initBackend( rendererInterface: RendererInterface, }) => { agent.setRendererInterface(id, rendererInterface); - rendererInterface.walkTree(); + + // Now that the Store and the renderer interface are connected, + // it's time to flush the pending operation codes to the frontend. + rendererInterface.flushInitialOperations(); } ), diff --git a/src/backend/renderer.js b/src/backend/renderer.js index 8f9d866a41..821060fc78 100644 --- a/src/backend/renderer.js +++ b/src/backend/renderer.js @@ -567,6 +567,7 @@ export function attach( } let pendingOperations: Uint32Array = new Uint32Array(0); + let pendingOperationsQueue: Array | null = []; function addOperation( newAction: Uint32Array, @@ -604,7 +605,16 @@ export function attach( // Let the frontend know about tree operations. // The first value in this array will identify which root it corresponds to, // so we do no longer need to dispatch a separate root-committed event. - hook.emit('operations', pendingOperations); + if (pendingOperationsQueue !== null) { + // Until the frontend has been connected, store the tree operations. + // This will let us avoid walking the tree later when the frontend connects, + // and it enables the Profiler's reload-and-profile functionality to work as well. + pendingOperationsQueue.push(pendingOperations); + } else { + // If we've already connected to the frontend, just pass the operations through. + hook.emit('operations', pendingOperations); + } + pendingOperations = new Uint32Array(0); } @@ -914,31 +924,46 @@ export function attach( // We don't patch any methods so there is no cleanup. } - function walkTree() { - // Hydrate all the roots for the first time. - hook.getFiberRoots(rendererID).forEach(root => { - currentRootID = getFiberID(getPrimaryFiber(root.current)); + function flushInitialOperations() { + const localPendingOperationsQueue = pendingOperationsQueue; - if (isProfiling) { - // If profiling is active, store commit time and duration, and the current interactions. - // The frontend may request this information after profiling has stopped. - currentCommitProfilingMetadata = { - actualDurations: [], - commitTime: performance.now() - profilingStartTime, - interactions: Array.from(root.memoizedInteractions).map( - (interaction: Interaction) => ({ - ...interaction, - timestamp: interaction.timestamp - profilingStartTime, - }) - ), - maxActualDuration: 0, - }; - } + pendingOperationsQueue = null; - mountFiber(root.current, null); - flushPendingEvents(root); - currentRootID = -1; - }); + if ( + localPendingOperationsQueue !== null && + localPendingOperationsQueue.length > 0 + ) { + // We may have already queued up some operations before the frontend connected + // If so, let the frontend know about them. + localPendingOperationsQueue.forEach(pendingOperations => { + hook.emit('operations', pendingOperations); + }); + } else { + // If we have not been profiling, then we can just walk the tree and build up its current state as-is. + hook.getFiberRoots(rendererID).forEach(root => { + currentRootID = getFiberID(getPrimaryFiber(root.current)); + + if (isProfiling) { + // If profiling is active, store commit time and duration, and the current interactions. + // The frontend may request this information after profiling has stopped. + currentCommitProfilingMetadata = { + actualDurations: [], + commitTime: performance.now() - profilingStartTime, + interactions: Array.from(root.memoizedInteractions).map( + (interaction: Interaction) => ({ + ...interaction, + timestamp: interaction.timestamp - profilingStartTime, + }) + ), + maxActualDuration: 0, + }; + } + + mountFiber(root.current, null); + flushPendingEvents(root); + currentRootID = -1; + }); + } } function handleCommitFiberUnmount(fiber) { @@ -1623,6 +1648,7 @@ export function attach( return { cleanup, + flushInitialOperations, getCommitDetails, getFiberIDFromNative, getInteractions, @@ -1641,6 +1667,5 @@ export function attach( setInState, startProfiling, stopProfiling, - walkTree, }; } diff --git a/src/backend/types.js b/src/backend/types.js index 9e85dac6d2..8768715d41 100644 --- a/src/backend/types.js +++ b/src/backend/types.js @@ -82,6 +82,7 @@ export type ProfilingSummary = {| export type RendererInterface = { cleanup: () => void, + flushInitialOperations: () => void, getCommitDetails: (rootID: number, commitIndex: number) => CommitDetails, getNativeFromReactElement?: ?(component: Fiber) => ?NativeType, getFiberIDFromNative: ( @@ -108,7 +109,6 @@ export type RendererInterface = { setInState: (id: number, path: Array, value: any) => void, startProfiling: () => void, stopProfiling: () => void, - walkTree: () => void, }; export type Handler = (data: any) => void; diff --git a/src/devtools/views/Profiler/CommitTreeBuilder.js b/src/devtools/views/Profiler/CommitTreeBuilder.js index 92e85c62ad..2f714aaa9d 100644 --- a/src/devtools/views/Profiler/CommitTreeBuilder.js +++ b/src/devtools/views/Profiler/CommitTreeBuilder.js @@ -112,14 +112,9 @@ export function getCommitTree({ } } - console.error( + throw Error( `getCommitTree(): Unable to reconstruct tree for root "${rootID}" and commit ${commitIndex}` ); - - return { - nodes: new Map(), - rootID, - }; } function recursivelyIniitliazeTree( diff --git a/src/devtools/views/Profiler/FlamegraphChartBuilder.js b/src/devtools/views/Profiler/FlamegraphChartBuilder.js index df183d63d9..9a7339cd01 100644 --- a/src/devtools/views/Profiler/FlamegraphChartBuilder.js +++ b/src/devtools/views/Profiler/FlamegraphChartBuilder.js @@ -56,6 +56,11 @@ export function getChartData({ idToDepthMap.set(id, currentDepth); const node = ((nodes.get(id): any): Node); + + if (node == null) { + throw Error(`Could not find node with id "${id}" in commit tree`); + } + const name = node.displayName || 'Unknown'; const selfDuration = calculateSelfDuration(id, commitTree, commitDetails); diff --git a/src/devtools/views/Profiler/RankedChartBuilder.js b/src/devtools/views/Profiler/RankedChartBuilder.js index f900a6d3f0..b514cac3bc 100644 --- a/src/devtools/views/Profiler/RankedChartBuilder.js +++ b/src/devtools/views/Profiler/RankedChartBuilder.js @@ -41,6 +41,10 @@ export function getChartData({ actualDurations.forEach((actualDuration, id) => { const node = ((nodes.get(id): any): Node); + if (node == null) { + throw Error(`Could not find node with id "${id}" in commit tree`); + } + // Don't show the root node in this chart. if (node.parentID === 0) { return;