From 25b982a6cb64fe4a3e8c1712ba704660c3e8b290 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 21 Oct 2016 19:14:19 +0100 Subject: [PATCH 1/3] Build react-noop as a package This lets us consume it from the debugger. --- Gruntfile.js | 6 +++ grunt/tasks/npm-react-noop.js | 52 +++++++++++++++++++++++ grunt/tasks/npm-react-test.js | 2 +- gulpfile.js | 41 +++++++++++++++++- packages/react-noop-renderer/README.md | 4 ++ packages/react-noop-renderer/index.js | 3 ++ packages/react-noop-renderer/package.json | 20 +++++++++ 7 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 grunt/tasks/npm-react-noop.js create mode 100644 packages/react-noop-renderer/README.md create mode 100644 packages/react-noop-renderer/index.js create mode 100644 packages/react-noop-renderer/package.json diff --git a/Gruntfile.js b/Gruntfile.js index 71f3ffd258f5..0e74fa01bac5 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -94,6 +94,10 @@ module.exports = function(grunt) { grunt.registerTask('npm-react-test:release', npmReactTestRendererTasks.buildRelease); grunt.registerTask('npm-react-test:pack', npmReactTestRendererTasks.packRelease); + var npmReactNoopRendererTasks = require('./grunt/tasks/npm-react-noop'); + grunt.registerTask('npm-react-noop:release', npmReactNoopRendererTasks.buildRelease); + grunt.registerTask('npm-react-noop:pack', npmReactNoopRendererTasks.packRelease); + grunt.registerTask('version-check', function() { // Use gulp here. spawnGulp(['version-check'], null, this.async()); @@ -186,6 +190,8 @@ module.exports = function(grunt) { 'npm-react-addons:pack', 'npm-react-test:release', 'npm-react-test:pack', + 'npm-react-noop:release', + 'npm-react-noop:pack', 'compare_size', ]); diff --git a/grunt/tasks/npm-react-noop.js b/grunt/tasks/npm-react-noop.js new file mode 100644 index 000000000000..62fb60d34d57 --- /dev/null +++ b/grunt/tasks/npm-react-noop.js @@ -0,0 +1,52 @@ +'use strict'; + +var fs = require('fs'); +var grunt = require('grunt'); + +var src = 'packages/react-noop-renderer/'; +var dest = 'build/packages/react-noop-renderer/'; +var modSrc = 'build/node_modules/react-noop-renderer/lib'; +var lib = dest + 'lib/'; + +function buildRelease() { + if (grunt.file.exists(dest)) { + grunt.file.delete(dest); + } + + // Copy to build/packages/react-noop-renderer + var mappings = [].concat( + grunt.file.expandMapping('**/*', dest, {cwd: src}), + grunt.file.expandMapping('**/*', lib, {cwd: modSrc}), + grunt.file.expandMapping('{LICENSE,PATENTS}', dest) + ); + mappings.forEach(function(mapping) { + var mappingSrc = mapping.src[0]; + var mappingDest = mapping.dest; + if (grunt.file.isDir(mappingSrc)) { + grunt.file.mkdir(mappingDest); + } else { + grunt.file.copy(mappingSrc, mappingDest); + } + }); +} + +function packRelease() { + var done = this.async(); + var spawnCmd = { + cmd: 'npm', + args: ['pack', 'packages/react-noop-renderer'], + opts: { + cwd: 'build/', + }, + }; + grunt.util.spawn(spawnCmd, function() { + var buildSrc = 'build/react-noop-renderer-' + grunt.config.data.pkg.version + '.tgz'; + var buildDest = 'build/packages/react-noop-renderer.tgz'; + fs.rename(buildSrc, buildDest, done); + }); +} + +module.exports = { + buildRelease: buildRelease, + packRelease: packRelease, +}; diff --git a/grunt/tasks/npm-react-test.js b/grunt/tasks/npm-react-test.js index 370ff1fe5459..448da02472e1 100644 --- a/grunt/tasks/npm-react-test.js +++ b/grunt/tasks/npm-react-test.js @@ -13,7 +13,7 @@ function buildRelease() { grunt.file.delete(dest); } - // Copy to build/packages/react-native-renderer + // Copy to build/packages/react-test-renderer var mappings = [].concat( grunt.file.expandMapping('**/*', dest, {cwd: src}), grunt.file.expandMapping('**/*', lib, {cwd: modSrc}), diff --git a/gulpfile.js b/gulpfile.js index df41040cf581..a0261f5e871f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -92,6 +92,20 @@ var paths = { ], lib: 'build/node_modules/react-test-renderer/lib', }, + reactNoopRenderer: { + src: [ + 'src/renderers/noop/**/*.js', + 'src/renderers/shared/**/*.js', + + 'src/ReactVersion.js', + 'src/shared/**/*.js', + '!src/shared/vendor/**/*.js', + '!src/**/__benchmarks__/**/*.js', + '!src/**/__tests__/**/*.js', + '!src/**/__mocks__/**/*.js', + ], + lib: 'build/node_modules/react-noop-renderer/lib', + }, }; var moduleMapBase = Object.assign( @@ -148,6 +162,13 @@ var moduleMapReactTestRenderer = Object.assign( moduleMapBase ); +var moduleMapReactNoopRenderer = Object.assign( + {}, + rendererSharedState, + moduleMapBase +); + + var errorCodeOpts = { errorMapFilePath: 'scripts/error-codes/codes.json', }; @@ -180,6 +201,13 @@ var babelOptsReactTestRenderer = { ], }; +var babelOptsReactNoopRenderer = { + plugins: [ + devExpressionWithCodes, // this pass has to run before `rewrite-modules` + [babelPluginModules, {map: moduleMapReactNoopRenderer}], + ], +}; + gulp.task('eslint', getTask('eslint')); gulp.task('lint', ['eslint']); @@ -194,6 +222,7 @@ gulp.task('react:clean', function() { paths.reactDOM.lib, paths.reactNative.lib, paths.reactTestRenderer.lib, + paths.reactNoopRenderer.lib, ]); }); @@ -225,7 +254,14 @@ gulp.task('react:modules', function() { .pipe(stripProvidesModule()) .pipe(babel(babelOptsReactTestRenderer)) .pipe(flatten()) - .pipe(gulp.dest(paths.reactTestRenderer.lib)) + .pipe(gulp.dest(paths.reactTestRenderer.lib)), + + gulp + .src(paths.reactNoopRenderer.src) + .pipe(stripProvidesModule()) + .pipe(babel(babelOptsReactNoopRenderer)) + .pipe(flatten()) + .pipe(gulp.dest(paths.reactNoopRenderer.lib)) ); }); @@ -234,7 +270,8 @@ gulp.task('react:extract-errors', function() { gulp.src(paths.react.src).pipe(extractErrors(errorCodeOpts)), gulp.src(paths.reactDOM.src).pipe(extractErrors(errorCodeOpts)), gulp.src(paths.reactNative.src).pipe(extractErrors(errorCodeOpts)), - gulp.src(paths.reactTestRenderer.src).pipe(extractErrors(errorCodeOpts)) + gulp.src(paths.reactTestRenderer.src).pipe(extractErrors(errorCodeOpts)), + gulp.src(paths.reactNoopRenderer.src).pipe(extractErrors(errorCodeOpts)) ); }); diff --git a/packages/react-noop-renderer/README.md b/packages/react-noop-renderer/README.md new file mode 100644 index 000000000000..1bd535c9f7bf --- /dev/null +++ b/packages/react-noop-renderer/README.md @@ -0,0 +1,4 @@ +# `react-noop-renderer` + +This package is the renderer we use for debugging [Fiber](https://github.com/facebook/react/issues/6170). +It is not intended to be used directly. diff --git a/packages/react-noop-renderer/index.js b/packages/react-noop-renderer/index.js new file mode 100644 index 000000000000..f7371b224f72 --- /dev/null +++ b/packages/react-noop-renderer/index.js @@ -0,0 +1,3 @@ +'use strict'; + +module.exports = require('./lib/ReactNoop'); diff --git a/packages/react-noop-renderer/package.json b/packages/react-noop-renderer/package.json new file mode 100644 index 000000000000..fe103cc7b85a --- /dev/null +++ b/packages/react-noop-renderer/package.json @@ -0,0 +1,20 @@ +{ + "name": "react-noop-renderer", + "version": "16.0.0-alpha", + "private": true, + "description": "React package for testing the Fiber reconciler.", + "main": "index.js", + "repository": "facebook/react", + "license": "BSD-3-Clause", + "dependencies": { + "fbjs": "^0.8.4", + "object-assign": "^4.1.0" + }, + "files": [ + "LICENSE", + "PATENTS", + "README.md", + "index.js", + "lib/" + ] +} From 5b957ac16e52e563c921d96f993f8e450fd15df1 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Mon, 24 Oct 2016 15:19:26 +0100 Subject: [PATCH 2/3] Add instrumentation to Fiber --- .../shared/fiber/ReactFiberInstrumentation.js | 23 ++++++++++++++ .../shared/fiber/ReactFiberReconciler.js | 16 ++++++++++ .../shared/fiber/ReactFiberScheduler.js | 31 ++++++++++++++----- 3 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 src/renderers/shared/fiber/ReactFiberInstrumentation.js diff --git a/src/renderers/shared/fiber/ReactFiberInstrumentation.js b/src/renderers/shared/fiber/ReactFiberInstrumentation.js new file mode 100644 index 000000000000..bb2abc533b7f --- /dev/null +++ b/src/renderers/shared/fiber/ReactFiberInstrumentation.js @@ -0,0 +1,23 @@ +/** + * Copyright 2013-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 ReactFiberInstrumentation + * @flow + */ + +'use strict'; + +// This lets us hook into Fiber to debug what it's doing. +// See https://github.com/facebook/react/pull/8033. +// This is not part of the public API, not even for React DevTools. +// You may only inject a debugTool if you work on React Fiber itself. +var ReactFiberInstrumentation = { + debugTool: null, +}; + +module.exports = ReactFiberInstrumentation; diff --git a/src/renderers/shared/fiber/ReactFiberReconciler.js b/src/renderers/shared/fiber/ReactFiberReconciler.js index 82a6175fd0c6..c7aeac0fbd6b 100644 --- a/src/renderers/shared/fiber/ReactFiberReconciler.js +++ b/src/renderers/shared/fiber/ReactFiberReconciler.js @@ -20,6 +20,10 @@ import type { PriorityLevel } from 'ReactPriorityLevel'; var { createFiberRoot } = require('ReactFiberRoot'); var ReactFiberScheduler = require('ReactFiberScheduler'); +if (__DEV__) { + var ReactFiberInstrumentation = require('ReactFiberInstrumentation'); +} + type Deadline = { timeRemaining : () => number }; @@ -80,6 +84,10 @@ module.exports = function(config : HostConfig) : scheduleWork(root); + if (__DEV__ && ReactFiberInstrumentation.debugTool) { + ReactFiberInstrumentation.debugTool.onMountContainer(root); + } + // It may seem strange that we don't return the root here, but that will // allow us to have containers that are in the middle of the tree instead // of being roots. @@ -93,6 +101,10 @@ module.exports = function(config : HostConfig) : root.current.pendingProps = element; scheduleWork(root); + + if (__DEV__ && ReactFiberInstrumentation.debugTool) { + ReactFiberInstrumentation.debugTool.onUpdateContainer(root); + } }, unmountContainer(container : OpaqueNode) : void { @@ -102,6 +114,10 @@ module.exports = function(config : HostConfig) : root.current.pendingProps = []; scheduleWork(root); + + if (__DEV__ && ReactFiberInstrumentation.debugTool) { + ReactFiberInstrumentation.debugTool.onUnmountContainer(root); + } }, performWithPriority, diff --git a/src/renderers/shared/fiber/ReactFiberScheduler.js b/src/renderers/shared/fiber/ReactFiberScheduler.js index 99c8682a17eb..17f2ba726ae4 100644 --- a/src/renderers/shared/fiber/ReactFiberScheduler.js +++ b/src/renderers/shared/fiber/ReactFiberScheduler.js @@ -42,6 +42,10 @@ var { HostContainer, } = require('ReactTypeOfWork'); +if (__DEV__) { + var ReactFiberInstrumentation = require('ReactFiberInstrumentation'); +} + var timeHeuristicForUnitOfWork = 1; module.exports = function(config : HostConfig) { @@ -274,15 +278,28 @@ module.exports = function(config : HostConfig) { // means that we don't need an additional field on the work in // progress. const current = workInProgress.alternate; - const next = beginWork(current, workInProgress, nextPriorityLevel); - if (next) { - // If this spawns new work, do that next. - return next; - } else { - // Otherwise, complete the current work. - return completeUnitOfWork(workInProgress); + if (__DEV__ && ReactFiberInstrumentation.debugTool) { + ReactFiberInstrumentation.debugTool.onWillBeginWork(workInProgress); + } + // See if beginning this work spawns more work. + let next = beginWork(current, workInProgress, nextPriorityLevel); + if (__DEV__ && ReactFiberInstrumentation.debugTool) { + ReactFiberInstrumentation.debugTool.onDidBeginWork(workInProgress); + } + + if (!next) { + if (__DEV__ && ReactFiberInstrumentation.debugTool) { + ReactFiberInstrumentation.debugTool.onWillCompleteWork(workInProgress); + } + // If this doesn't spawn new work, complete the current work. + next = completeUnitOfWork(workInProgress); + if (__DEV__ && ReactFiberInstrumentation.debugTool) { + ReactFiberInstrumentation.debugTool.onDidCompleteWork(workInProgress); + } } + + return next; } function performDeferredWork(deadline) { From 4f0b8f0e824c068864ba779fa5be4a8fd5fec605 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Fri, 21 Oct 2016 20:49:22 +0100 Subject: [PATCH 3/3] Check in Fiber Debugger --- examples/fiber/debugger/.gitignore | 15 + examples/fiber/debugger/README.md | 25 + examples/fiber/debugger/package.json | 20 + examples/fiber/debugger/public/favicon.ico | Bin 0 -> 24838 bytes examples/fiber/debugger/public/index.html | 13 + examples/fiber/debugger/src/App.js | 215 + examples/fiber/debugger/src/Editor.js | 35 + examples/fiber/debugger/src/Fibers.js | 329 + examples/fiber/debugger/src/describeFibers.js | 92 + examples/fiber/debugger/src/index.css | 15 + examples/fiber/debugger/src/index.js | 9 + examples/fiber/debugger/yarn.lock | 5384 +++++++++++++++++ 12 files changed, 6152 insertions(+) create mode 100644 examples/fiber/debugger/.gitignore create mode 100644 examples/fiber/debugger/README.md create mode 100644 examples/fiber/debugger/package.json create mode 100644 examples/fiber/debugger/public/favicon.ico create mode 100644 examples/fiber/debugger/public/index.html create mode 100644 examples/fiber/debugger/src/App.js create mode 100644 examples/fiber/debugger/src/Editor.js create mode 100644 examples/fiber/debugger/src/Fibers.js create mode 100644 examples/fiber/debugger/src/describeFibers.js create mode 100644 examples/fiber/debugger/src/index.css create mode 100644 examples/fiber/debugger/src/index.js create mode 100644 examples/fiber/debugger/yarn.lock diff --git a/examples/fiber/debugger/.gitignore b/examples/fiber/debugger/.gitignore new file mode 100644 index 000000000000..6c96c5cff124 --- /dev/null +++ b/examples/fiber/debugger/.gitignore @@ -0,0 +1,15 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules + +# testing +coverage + +# production +build + +# misc +.DS_Store +.env +npm-debug.log diff --git a/examples/fiber/debugger/README.md b/examples/fiber/debugger/README.md new file mode 100644 index 000000000000..f52646d9c654 --- /dev/null +++ b/examples/fiber/debugger/README.md @@ -0,0 +1,25 @@ +# Fiber Debugger + +This is a debugger handy for visualizing how [Fiber](https://github.com/facebook/react/issues/6170) works internally. + +**It is only meant to be used by React contributors, and not by React users.** + +It is likely that it might get broken at some point. If it's broken, ping [Dan](https://twitter.com/dan_abramov). + +### Running + +First, `npm run build` in React root repo folder. + +Then `npm install` and `npm start` in this folder. + +Open `http://localhost:3000` in Chrome. + +### Features + +* Edit code that uses `ReactNoop` renderer +* Visualize how relationships between fibers change over time +* Current tree is displayed in green + +![fiber debugger](https://d17oy1vhnax1f7.cloudfront.net/items/3R2W1H2M3a0h3p1l133r/Screen%20Recording%202016-10-21%20at%2020.41.gif?v=e4323e51) + + diff --git a/examples/fiber/debugger/package.json b/examples/fiber/debugger/package.json new file mode 100644 index 000000000000..eba0df6fcdc8 --- /dev/null +++ b/examples/fiber/debugger/package.json @@ -0,0 +1,20 @@ +{ + "name": "react-fiber-debugger", + "version": "0.0.1", + "private": true, + "devDependencies": { + "react-scripts": "0.6.1" + }, + "dependencies": { + "dagre": "^0.7.4", + "pretty-format": "^4.2.1", + "react": "^15.3.2", + "react-dom": "^15.3.2", + "react-draggable": "^2.2.2", + "react-motion": "^0.4.5" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build" + } +} diff --git a/examples/fiber/debugger/public/favicon.ico b/examples/fiber/debugger/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..5c125de5d897c1ff5692a656485b3216123dcd89 GIT binary patch literal 24838 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 + + + + + + + React App + + +
+ + diff --git a/examples/fiber/debugger/src/App.js b/examples/fiber/debugger/src/App.js new file mode 100644 index 000000000000..dd224428869c --- /dev/null +++ b/examples/fiber/debugger/src/App.js @@ -0,0 +1,215 @@ +import React, { Component } from 'react'; +import Draggable from 'react-draggable'; +import ReactNoop from '../../../../build/packages/react-noop-renderer'; +import ReactFiberInstrumentation from '../../../../build/packages/react-noop-renderer/lib/ReactFiberInstrumentation'; +import Editor from './Editor'; +import Fibers from './Fibers'; +import describeFibers from './describeFibers'; + +function getFiberState(root, workInProgress) { + if (!root) { + return null; + } + return describeFibers(root.current, workInProgress); +} + +const defaultCode = ` +log('Render
Hello
'); +ReactNoop.render(
Hello
); +ReactNoop.flush(); + +log('Render

Goodbye

'); +ReactNoop.render(

Goodbye

); +ReactNoop.flush(); +`; + +class App extends Component { + constructor(props) { + super(props); + this.state = { + code: defaultCode, + isEditing: false, + history: [], + currentStep: 0, + show: { + alt: false, + child: true, + sibling: true, + return: false, + fx: false, + progressedChild: false, + progressedDel: false + } + }; + } + + componentDidMount() { + this.runCode(this.state.code); + } + + runCode(code) { + let currentStage; + let currentRoot; + + ReactFiberInstrumentation.debugTool = { + onMountContainer: (root) => { + currentRoot = root; + }, + onUpdateContainer: (root) => { + currentRoot = root; + }, + onWillBeginWork: (fiber) => { + const fibers = getFiberState(currentRoot, fiber); + const stage = currentStage; + this.setState(({ history }) => ({ + history: [ + ...history, { + action: 'willBeginWork', + fibers, + stage + } + ] + })); + }, + onDidBeginWork: (fiber) => { + const fibers = getFiberState(currentRoot, fiber); + const stage = currentStage; + this.setState(({ history }) => ({ + history: [ + ...history, { + action: 'didBeginWork', + fibers, + stage + } + ] + })); + }, + onWillCompleteWork: (fiber) => { + const fibers = getFiberState(currentRoot, fiber); + const stage = currentStage; + this.setState(({ history }) => ({ + history: [ + ...history, { + action: 'willCompleteWork', + fibers, + stage + } + ] + })); + }, + onDidCompleteWork: (fiber) => { + const fibers = getFiberState(currentRoot, fiber); + const stage = currentStage; + this.setState(({ history }) => ({ + history: [ + ...history, { + action: 'didCompleteWork', + fibers, + stage + } + ] + })); + }, + }; + window.React = React; + window.ReactNoop = ReactNoop; + window.log = s => currentStage = s; + // eslint-disable-next-line + eval(window.Babel.transform(code, { + presets: ['react', 'es2015'] + }).code); + } + + handleEdit = (e) => { + e.preventDefault(); + this.setState({ + isEditing: true + }); + } + + handleCloseEdit = (nextCode) => { + this.setState({ + isEditing: false, + history: [], + currentStep: 0, + code: nextCode + }); + this.runCode(nextCode); + } + + render() { + const { history, currentStep, isEditing, code } = this.state; + if (isEditing) { + return ; + } + + const { fibers, action, stage } = history[currentStep] || {}; + let friendlyAction; + + if (fibers) { + let wipFiber = fibers.descriptions[fibers.workInProgressID]; + let friendlyFiber = wipFiber.type || wipFiber.tag + ' #' + wipFiber.id; + switch (action) { + case 'willBeginWork': + friendlyAction = 'Before BEGIN phase on ' + friendlyFiber; + break; + case 'didBeginWork': + friendlyAction = 'After BEGIN phase on ' + friendlyFiber; + break; + case 'willCompleteWork': + friendlyAction = 'Before COMPLETE phase on ' + friendlyFiber; + break; + case 'didCompleteWork': + friendlyAction = 'After COMPLETE phase on ' + friendlyFiber; + break; + default: + throw new Error('Unknown action'); + } + } + + return ( +
+ {fibers && + + + + } +
+ this.setState({ currentStep: Number(e.target.value) })} + /> +

Step {currentStep}: {friendlyAction} (Edit)

+ {stage &&

Stage: {stage}

} + {Object.keys(this.state.show).map(key => + + )} +
+
+ ); + } +} + +export default App; diff --git a/examples/fiber/debugger/src/Editor.js b/examples/fiber/debugger/src/Editor.js new file mode 100644 index 000000000000..644d04f6d490 --- /dev/null +++ b/examples/fiber/debugger/src/Editor.js @@ -0,0 +1,35 @@ +import React, { Component } from 'react'; + +class Editor extends Component { + constructor(props) { + super(props); + this.state = { + code: props.code + }; + } + + render() { + return ( +
+