react-perf-devtool
Advanced tools
Comparing version 3.0.0-beta1 to 3.0.0-beta10
{ | ||
"name": "react-perf-devtool", | ||
"version": "3.0.0-beta1", | ||
"description": | ||
"A chrome devtool extension for inspecting performance of React Components", | ||
"version": "3.0.0-beta10", | ||
"description": "A chrome devtool extension for inspecting performance of React Components", | ||
"main": "src/npm/index.js", | ||
"files": ["src"], | ||
"files": [ | ||
"src" | ||
], | ||
"author": "Nitin Tulswani", | ||
@@ -12,3 +13,4 @@ "license": "MIT", | ||
"react": "^16.2.0", | ||
"react-dom": "^16.2.0" | ||
"react-dom": "^16.2.0", | ||
"react-syntax-highlighter": "^6.1.1" | ||
}, | ||
@@ -30,9 +32,6 @@ "devDependencies": { | ||
"test": "jest", | ||
"build:watch": | ||
"rm -rf ./extension/build && NODE_ENV=production ./node_modules/.bin/webpack --watch --config ./webpack/webpack.config.js --progress", | ||
"build": | ||
"rm -rf ./extension/build && NODE_ENV=production ./node_modules/.bin/webpack --config ./webpack/webpack.config.js --progress", | ||
"build:watch": "rm -rf ./extension/build && NODE_ENV=production ./node_modules/.bin/webpack --watch --config ./webpack/webpack.config.js --progress", | ||
"build": "rm -rf ./extension/build && NODE_ENV=production ./node_modules/.bin/webpack --config ./webpack/webpack.config.js --progress", | ||
"precommit": "lint-staged", | ||
"format": | ||
"find src -name '*.js' | xargs ./node_modules/.bin/prettier --write --no-semi --single-quote", | ||
"format": "find src -name '*.js' | xargs ./node_modules/.bin/prettier --write --no-semi --single-quote", | ||
"generate": "yarn build && zip -r extension.zip ./extension" | ||
@@ -39,0 +38,0 @@ }, |
@@ -5,5 +5,22 @@ const React = require('react') | ||
const Results = require('./Results') | ||
const ErrorComponent = require('./ErrorComponent') | ||
// Stores the measures | ||
let store = [] | ||
const commonStyles = { fontWeight: 500, padding: '8px' } | ||
// These fields are evaluated in the inspectedWindow to get information about measures. | ||
const executeCode = { | ||
measuresLength: 'JSON.stringify(__REACT_PERF_DEVTOOL_GLOBAL_STORE__.length)', | ||
measures: 'JSON.stringify(__REACT_PERF_DEVTOOL_GLOBAL_STORE__.measures)', | ||
rawMeasures: | ||
'JSON.stringify(__REACT_PERF_DEVTOOL_GLOBAL_STORE__.rawMeasures)', | ||
clear: `__REACT_PERF_DEVTOOL_GLOBAL_STORE__ = { | ||
length: 0, | ||
measures: [], | ||
rawMeasures: [], | ||
}`, | ||
} | ||
/** | ||
@@ -17,7 +34,8 @@ This is the main component that renders the table, containing information about | ||
timer = null | ||
evaluate = chrome.devtools.inspectedWindow.eval | ||
refresh = chrome.devtools.inspectedWindow.reload | ||
panelStyles = { | ||
color: chrome.devtools.panels.themeName === 'dark' ? 'white' : 'black', | ||
} | ||
ERROR_MSG = ` | ||
An error occurred while collecting the measures. Please try again by reloading the inspected window or refresh the page. | ||
` | ||
constructor(props) { | ||
@@ -33,3 +51,2 @@ super(props) | ||
hasError: false, // Track errors, occurred when collecting the measures. | ||
errorMsg: null | ||
} | ||
@@ -48,21 +65,16 @@ } | ||
// Clear the timer. | ||
// this.observer.disconnect() | ||
clearInterval(this.timer) | ||
} | ||
updateErrorState = () => | ||
this.setState({ hasError: true, errorMsg: this.ERROR_MSG }) | ||
getMeasuresLength = () => { | ||
chrome.devtools.inspectedWindow.eval( | ||
"JSON.stringify(__REACT_PERF_DEVTOOL_GLOBAL_STORE___.length)", | ||
(count, err) => { | ||
if (err) { | ||
this.updateErrorState() | ||
return | ||
} | ||
this.evaluate(executeCode['measuresLength'], (count, err) => { | ||
if (err) { | ||
this.setState({ hasError: true }) | ||
return | ||
} | ||
// Update the event count. | ||
this.updateEventsCount(JSON.parse(count)) | ||
} | ||
) | ||
// Update the event count. | ||
this.updateEventsCount(JSON.parse(count)) | ||
}) | ||
} | ||
@@ -88,31 +100,26 @@ | ||
getMeasures = () => { | ||
chrome.devtools.inspectedWindow.eval( | ||
"JSON.stringify(__REACT_PERF_DEVTOOL_GLOBAL_STORE___.measures)", | ||
(measures, err) => { | ||
if (err) { | ||
this.updateErrorState() | ||
return | ||
} | ||
// Returns the performance entries which are not parsed and not aggregated | ||
this.getRawMeasures() | ||
this.getRawMeasures() | ||
this.evaluate(executeCode['measures'], (measures, err) => { | ||
if (err) { | ||
this.setState({ hasError: true }) | ||
return | ||
} | ||
// Update the state. | ||
this.updateMeasures(JSON.parse(measures)) | ||
} | ||
) | ||
// Update the state. | ||
this.updateMeasures(JSON.parse(measures)) | ||
}) | ||
} | ||
getRawMeasures = () => { | ||
chrome.devtools.inspectedWindow.eval( | ||
"JSON.stringify(__REACT_PERF_DEVTOOL_GLOBAL_STORE___.rawMeasures)", | ||
(measures, err) => { | ||
if (err) { | ||
this.updateErrorState() | ||
return | ||
} | ||
this.setState({ | ||
rawMeasures: JSON.parse(measures) | ||
}) | ||
this.evaluate(executeCode['rawMeasures'], (measures, err) => { | ||
if (err) { | ||
this.setState({ hasError: true }) | ||
return | ||
} | ||
) | ||
this.setState({ | ||
rawMeasures: JSON.parse(measures), | ||
}) | ||
}) | ||
} | ||
@@ -133,3 +140,3 @@ | ||
clearMeasures = () => chrome.devtools.inspectedWindow.eval("__REACT_PERF_DEVTOOL_GLOBAL_STORE___ = {}") | ||
clearMeasures = () => this.evaluate(executeCode['clear']) | ||
@@ -143,2 +150,4 @@ // Clear the panel content. | ||
totalTime: 0, | ||
rawMeasures: [], | ||
pendingEvents: 0, | ||
}) | ||
@@ -155,7 +164,7 @@ | ||
this.clear() | ||
this.browserReload() | ||
// Set the state back to loading (this avoids a flash when the inspected window is reloaded) | ||
this.setState({ loading: true }) | ||
this.browserReload() | ||
chrome.devtools.inspectedWindow.reload() | ||
@@ -165,11 +174,4 @@ } | ||
render() { | ||
const commonStyles = { fontWeight: 500, padding: '8px' } | ||
return ( | ||
<div | ||
style={{ | ||
color: | ||
chrome.devtools.panels.themeName === 'dark' ? 'white' : 'black', | ||
}} | ||
> | ||
<div style={this.panelStyles}> | ||
<div style={{ display: 'inlineBlock' }}> | ||
@@ -184,3 +186,3 @@ <button onClick={this.clear}>Clear</button> | ||
{this.state.hasError ? ( | ||
<div style={commonStyles}>{this.state.errorMsg}</div> | ||
<ErrorComponent /> | ||
) : ( | ||
@@ -187,0 +189,0 @@ <React.Fragment> |
var getReactPerformanceData = require('../shared/parse') | ||
var generateDataFromMeasures = require('../shared/generate') | ||
function registerListener() { | ||
/** | ||
This registers an observer that listens to the React performance measurement event. | ||
It hooks an object containing information about the events and performance measures of React components to the | ||
global state (window object) which can then be accessed inside the inspected window using eval(). | ||
With every re-render, this object is updated with new measures and events count. | ||
The extension takes care of clearing up the memory (required to store this object) and also the cache. | ||
Calculating and aggregating the results happens inside the app frame and not in the devtool. It has its own benefits. | ||
* These measures can be send to a server for analyses | ||
* Measures can be logged to a console | ||
* Particular measures can be inspected in the console with the help of configuration object | ||
* This also gives control to the developer on how to manage and inspect the measures apart from using the extension | ||
Trade-offs of version 1 API: | ||
* Need to update the commonjs react-dom development bundle | ||
* No way of sending the measures from the app frame to the console | ||
* Need to query measures rather than listening to an event once | ||
* No control on how to inspect the measures for a particular use case (for eg - render and update performance of a component) | ||
Options to passed to listener: | ||
* log (log to console) | ||
* port (port number to send the data to console) | ||
Callback (optional): A callback can also be passed while registering the listener. The callback receives the parsed and aggregated results of the | ||
performance measures. | ||
*/ | ||
function registerListener({ shouldLog, port }, callback) { | ||
var observer = new window.PerformanceObserver(list => { | ||
// window.__REACT_PERF_DEVTOOL_GLOBAL_STORE___ = list.getEntries() | ||
var measures = generateDataFromMeasures( | ||
getReactPerformanceData(list.getEntries()) | ||
) | ||
var measures = generateDataFromMeasures(getReactPerformanceData(list.getEntries())) | ||
if (callback && typeof callback === 'function') { | ||
callback(measures) | ||
} | ||
window.__REACT_PERF_DEVTOOL_GLOBAL_STORE___ = { | ||
name: 'React Performance Measures', | ||
// React Perf Devtool hook | ||
window.__REACT_PERF_DEVTOOL_GLOBAL_STORE__ = { | ||
measures, | ||
length: list.getEntries().length, | ||
rawMeasures: list.getEntries() | ||
rawMeasures: list.getEntries(), | ||
} | ||
// For logging to console | ||
if (shouldLog) { | ||
logToConsole(port, measures) | ||
} | ||
}) | ||
observer.observe({ | ||
entryTypes: ['measure'] | ||
}); | ||
entryTypes: ['measure'], | ||
}) | ||
} | ||
module.exports = registerListener | ||
function logToConsole(port, measures) { | ||
measures.forEach( | ||
({ | ||
componentName, | ||
mount, | ||
render, | ||
update, | ||
unmount, | ||
totalTimeSpent, | ||
percentTimeSpent, | ||
numberOfInstances, | ||
componentWillMount, | ||
componentDidMount, | ||
componentWillReceiveProps, | ||
shouldComponentUpdate, | ||
componentWillUpdate, | ||
componentDidUpdate, | ||
componentWillUnmount, | ||
}) => { | ||
const data = { | ||
component: componentName, | ||
mount, | ||
render, | ||
update, | ||
unmount, | ||
totalTimeSpent, | ||
percentTimeSpent, | ||
numberOfInstances, | ||
componentWillMount, | ||
componentDidMount, | ||
componentWillReceiveProps, | ||
shouldComponentUpdate, | ||
componentWillUpdate, | ||
componentDidUpdate, | ||
componentWillUnmount, | ||
} | ||
window.navigator.sendBeacon( | ||
`http://127.0.0.1:${ | ||
port !== undefined && typeof port === 'number' ? port : 8080 | ||
}`, | ||
JSON.stringify(data, null, 2) | ||
) | ||
} | ||
) | ||
} | ||
// function logToConsole(measures) { | ||
// measures.forEach(({ componentName, mount, render, update }) => { | ||
// const data = { | ||
// componentName, | ||
// mount, | ||
// render, | ||
// update, | ||
// } | ||
// | ||
// window.navigator.sendBeacon('http://127.0.0.1:3000', JSON.stringify(data)) | ||
// }) | ||
// } | ||
module.exports = registerListener |
Sorry, the diff of this file is not supported yet
50264
21
871
3
+ Addedbabel-runtime@6.26.0(transitive)
+ Addedcharacter-entities@1.2.4(transitive)
+ Addedcharacter-entities-legacy@1.1.4(transitive)
+ Addedcharacter-reference-invalid@1.1.4(transitive)
+ Addedclipboard@2.0.11(transitive)
+ Addedcomma-separated-tokens@1.0.8(transitive)
+ Addedcore-js@2.6.12(transitive)
+ Addeddelegate@3.2.0(transitive)
+ Addedfault@1.0.4(transitive)
+ Addedformat@0.2.2(transitive)
+ Addedgood-listener@1.2.2(transitive)
+ Addedhast-util-parse-selector@2.2.5(transitive)
+ Addedhastscript@5.1.2(transitive)
+ Addedhighlight.js@9.12.0(transitive)
+ Addedis-alphabetical@1.0.4(transitive)
+ Addedis-alphanumerical@1.0.4(transitive)
+ Addedis-decimal@1.0.4(transitive)
+ Addedis-hexadecimal@1.0.4(transitive)
+ Addedlowlight@1.9.2(transitive)
+ Addedparse-entities@1.2.2(transitive)
+ Addedprismjs@1.17.11.29.0(transitive)
+ Addedproperty-information@5.6.0(transitive)
+ Addedreact-syntax-highlighter@6.1.2(transitive)
+ Addedrefractor@2.10.1(transitive)
+ Addedregenerator-runtime@0.11.1(transitive)
+ Addedselect@1.1.2(transitive)
+ Addedspace-separated-tokens@1.1.5(transitive)
+ Addedtiny-emitter@2.1.0(transitive)
+ Addedxtend@4.0.2(transitive)