-
Notifications
You must be signed in to change notification settings - Fork 47.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Build react-noop as a package This lets us consume it from the debugger. * Add instrumentation to Fiber * Check in Fiber Debugger
- Loading branch information
Showing
22 changed files
with
6,340 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" | ||
} | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.14.0/babel.min.js"></script> | ||
<title>React App</title> | ||
</head> | ||
<body> | ||
<div id="root"></div> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <div>Hello</div>'); | ||
ReactNoop.render(<div>Hello</div>); | ||
ReactNoop.flush(); | ||
log('Render <h1>Goodbye</h1>'); | ||
ReactNoop.render(<h1>Goodbye</h1>); | ||
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 <Editor code={code} onClose={this.handleCloseEdit} />; | ||
} | ||
|
||
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 ( | ||
<div style={{ height: '100%' }}> | ||
{fibers && | ||
<Draggable> | ||
<Fibers fibers={fibers} show={this.state.show} /> | ||
</Draggable> | ||
} | ||
<div style={{ | ||
width: '100%', | ||
textAlign: 'center', | ||
position: 'fixed', | ||
bottom: 0, | ||
padding: 10, | ||
zIndex: 1, | ||
backgroundColor: '#fafafa', | ||
border: '1px solid #ccc' | ||
}}> | ||
<input | ||
type="range" | ||
min={0} | ||
max={history.length - 1} | ||
value={currentStep} | ||
onChange={e => this.setState({ currentStep: Number(e.target.value) })} | ||
/> | ||
<p>Step {currentStep}: {friendlyAction} (<a style={{ color: 'gray' }} onClick={this.handleEdit} href='#'>Edit</a>)</p> | ||
{stage && <p>Stage: {stage}</p>} | ||
{Object.keys(this.state.show).map(key => | ||
<label style={{ marginRight: '10px' }} key={key}> | ||
<input | ||
type="checkbox" | ||
checked={this.state.show[key]} | ||
onChange={e => { | ||
this.setState(({ show }) => ({ | ||
show: {...show, [key]: !show[key]} | ||
})); | ||
}} /> | ||
{key} | ||
</label> | ||
)} | ||
</div> | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import React, { Component } from 'react'; | ||
|
||
class Editor extends Component { | ||
constructor(props) { | ||
super(props); | ||
this.state = { | ||
code: props.code | ||
}; | ||
} | ||
|
||
render() { | ||
return ( | ||
<div style={{ | ||
height: '100%', | ||
width: '100%' | ||
}}> | ||
<textarea | ||
value={this.state.code} | ||
onChange={e => this.setState({ code: e.target.value })} | ||
style={{ | ||
height: '80%', | ||
width: '100%', | ||
fontSize: '15px' | ||
}} /> | ||
<div style={{ height: '20%', textAlign: 'center' }}> | ||
<button onClick={() => this.props.onClose(this.state.code)} style={{ fontSize: 'large' }}> | ||
Run | ||
</button> | ||
</div> | ||
</div> | ||
) | ||
} | ||
} | ||
|
||
export default Editor; |
Oops, something went wrong.