@samitouri / QOS-React / commits / d3e29d4e54

[Fiber] Support React DevTools (#8818)

* Initial React DevTools support for Fiber * Record a newly failing irrelevant test This is fine because we don't use it in Stack anyway (at least not that part), and we also rely on Set/Map in other parts of code. The newly failing test is the one saying "it works without Map/Set". * Explicitly check for Fiber DevTools support This lets us ignore pre-Fiber DevTools instead of crashing them by injecting a different API. * Track the roots in DevTools instead * Lol Dan this is not how warnings work in our codebase * Move injection to the renderer * Notify DevTools about unmounts * Make it work in production * Fix lint and flow * Fixups * Address feedback

Dan Abramov committed Jan 27, 2017 at 22:50 UTC d3e29d4e54f696da915f9aec08202b6314a162a1
4 files changed +91 -1
src/renderers/dom/fiber/ReactDOMFiber.js
+8 -1
@@ -29,7 +29,7 @@ var ReactInputSelection = require('ReactInputSelection');
29 var ReactInstanceMap = require('ReactInstanceMap');
30 var ReactPortal = require('ReactPortal');
31 var { isValidElement } = require('React');
32 -
32 +var { injectInternals } = require('ReactFiberDevToolsHook');
33
34 var findDOMNode = require('findDOMNode');
35 var invariant = require('invariant');
@@ -407,4 +407,11 @@ var ReactDOM = {
407
408 };
409
410 +if (typeof injectInternals === 'function') {
411 + injectInternals({
412 + findFiberByHostInstance: ReactDOMComponentTree.getClosestInstanceFromNode,
413 + findHostInstanceByFiber: DOMRenderer.findHostInstance,
414 + });
415 +}
416 +
417 module.exports = ReactDOM;
src/renderers/shared/fiber/ReactFiberCommitWork.js
+5
@@ -25,6 +25,7 @@ var {
25 CoroutineComponent,
26 } = ReactTypeOfWork;
27 var { commitCallbacks } = require('ReactFiberUpdateQueue');
28 +var { onCommitUnmount } = require('ReactFiberDevToolsHook');
29
30 var {
31 Placement,
@@ -317,6 +318,10 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
318 // deletion, so don't let them throw. Host-originating errors should
319 // interrupt deletion, so it's okay
320 function commitUnmount(current : Fiber) : void {
321 + if (typeof onCommitUnmount === 'function') {
322 + onCommitUnmount(current);
323 + }
324 +
325 switch (current.tag) {
326 case ClassComponent: {
327 safelyDetachRef(current);
src/renderers/shared/fiber/ReactFiberDevToolsHook.js new
+74
@@ -0,0 +1,74 @@
1 +/**
2 + * Copyright 2013-present, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + *
9 + * @providesModule ReactFiberDevToolsHook
10 + * @flow
11 + */
12 +
13 +/* globals __REACT_DEVTOOLS_GLOBAL_HOOK__ */
14 +
15 +'use strict';
16 +
17 +import type { Fiber } from 'ReactFiber';
18 +import type { FiberRoot } from 'ReactFiberRoot';
19 +
20 +if (__DEV__) {
21 + var warning = require('warning');
22 +}
23 +
24 +let rendererID = null;
25 +let injectInternals = null;
26 +let onCommitRoot = null;
27 +let onCommitUnmount = null;
28 +if (
29 + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
30 + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.supportsFiber
31 +) {
32 + let {
33 + inject,
34 + onCommitFiberRoot,
35 + onCommitFiberUnmount,
36 + } = __REACT_DEVTOOLS_GLOBAL_HOOK__;
37 +
38 + injectInternals = function(internals : Object) {
39 + warning(rendererID == null, 'Cannot inject into DevTools twice.');
40 + rendererID = inject(internals);
41 + };
42 +
43 + onCommitRoot = function(root : FiberRoot) {
44 + if (rendererID == null) {
45 + return;
46 + }
47 + try {
48 + onCommitFiberRoot(rendererID, root);
49 + } catch (err) {
50 + // Catch all errors because it is unsafe to throw in the commit phase.
51 + if (__DEV__) {
52 + warning(false, 'React DevTools encountered an error: %s', err);
53 + }
54 + }
55 + };
56 +
57 + onCommitUnmount = function(fiber : Fiber) {
58 + if (rendererID == null) {
59 + return;
60 + }
61 + try {
62 + onCommitFiberUnmount(rendererID, fiber);
63 + } catch (err) {
64 + // Catch all errors because it is unsafe to throw in the commit phase.
65 + if (__DEV__) {
66 + warning(false, 'React DevTools encountered an error: %s', err);
67 + }
68 + }
69 + };
70 +}
71 +
72 +exports.injectInternals = injectInternals;
73 +exports.onCommitRoot = onCommitRoot;
74 +exports.onCommitUnmount = onCommitUnmount;
src/renderers/shared/fiber/ReactFiberScheduler.js
+4
@@ -44,6 +44,7 @@ var ReactFeatureFlags = require('ReactFeatureFlags');
44 var getComponentName = require('getComponentName');
45
46 var { cloneFiber } = require('ReactFiber');
47 +var { onCommitRoot } = require('ReactFiberDevToolsHook');
48
49 var {
50 NoWork,
@@ -411,6 +412,9 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(config : HostConfig<T, P,
412 }
413
414 isCommitting = false;
415 + if (typeof onCommitRoot === 'function') {
416 + onCommitRoot(finishedWork.stateNode);
417 + }
418 if (__DEV__ && ReactFiberInstrumentation.debugTool) {
419 ReactFiberInstrumentation.debugTool.onCommitWork(finishedWork);
420 }