• Stars
    star
    2,324
  • Rank 19,815 (Top 0.4 %)
  • Language
    JavaScript
  • Created almost 7 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A browser developer tool extension to inspect performance of React components.

Looking for maintainers

React Performance Devtool

Build Status Release Status Author current-version extension npm downloads

A devtool for inspecting the performance of React Components



Table of contents

Introduction

React Performance Devtool is a browser extension for inspecting the performance of React Components. It statistically examines the performance of React components based on the measures which are collected by React using window.performance API.

Along with the browser extension, the measures can also be inspected in a console. See the usage section for more details.

This project started with a purpose of extending the work done by Will Chen on a proposal for React performance table. You can read more about it here.

Demo

Browser extension

A demo of the extension being used to examine the performance of React components on my website.

Log the measures to a console

Performance measures can also be logged to a console. With every re-render, measures are updated and logged to the console.

Uses

  • Remove or unmount the component instances which are not being used.

  • Inspect what is blocking or taking more time after an operation has been started.

  • Examine the table and see for which components, you need to write shouldComponentUpdate lifecycle hook.

  • Examine which components are taking more time to load.

Install

To use this devtool, you'll need to install a npm module which will register a listener (read more about this in usage section) and the browser extension.

Installing the extension

The below extensions represent the current stable release.

Installing the npm module

npm install react-perf-devtool

A umd build is also available via unpkg

<script crossorigin src="https://unpkg.com/[email protected]/lib/npm/hook.js"></script>

This extension and package also depends on react. Please make sure you have those installed as well.

Note - The npm module is important and required to use the devtool. So make sure you've installed it before using the browser extension.

Usage

This section of the documentation explain the usage of devtool and the API for registering an observer in a React app.

Browser Compatibility

react-perf-devtool relies on the native window.PerformanceObserver API that got added in Chrome v52 and Firefox v57. For further information, see the official Mozilla Docs here.

Using the browser extension

To use this devtool extension, you'll need to register an observer in your app which will observe a collection of data (performance measures) over a time.

Register observer

Registering an observer is very simple and is only one function call away. Let's see how!

const { registerObserver } = require('react-perf-devtool')

// assign the observer to the global scope, as the GC will delete it otherwise
window.observer = registerObserver()

You can place this code inside your index.js file (recommended) or any other file in your app.

Note - This should only be used in development mode when you need to inspect the performance of React components. Make sure to remove it when building for production.

Registering an observer hooks an object containing information about the events and performance measures of React components to the 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 and also the cache.

You can also pass an option object and an optional callback which receives an argument containing the parsed and aggregated measures

Using the callback

An optional callback can also be passed to registerObserver which receives parsed measures as its argument.

You can use this callback to inspect the parsed and aggregated measures, or you can integrate it with any other use case. You can also leverage these performance measures using Google Analytics by sending these measures to analytics dashboard . This process is documented here.

Example -

const { registerObserver } = require('react-perf-devtool')

function callback(measures) {
  // do something with the measures
}

// assign the observer to the global scope, as the GC will delete it otherwise
window.observer = registerObserver({}, callback)

After you've registered the observer, start your local development server and go to http://localhost:3000/.

Note - This extension works only for React 16 or above versions of it.

After you've installed the extension successfully, you'll see a tab called React Performance in Chrome Developer Tools.

Printing the measures to the console

The performance measures can also be logged to the console. However, the process of printing the measures is not direct. You'll need to set up a server which will listen the measures. For this, you can use micro by Zeit which is a HTTP microservice.

npm install --save micro

You can pass an option object as an argument to registerObserver to enable logging and setting up a port number.

Using the option object

{
  shouldLog: boolean, // default value: false
  port: number // default value: 8080
  timeout: number // default value: 2000
}

You can pass three properties to the option object, shouldLog and port.

  • shouldLog - It takes a boolean value. If set to true, measures will be logged to the console.

  • port - Port number for the server where the measures will be send

  • timeout - A timeout value to defer the initialisation of the extension.

If your application takes time to load, it's better to defer the initialisation of extension by specifying the timeout value through timeout property. This ensures that the extension will load only after your application has properly loaded in the browser so that the updated measures can be rendered. However, you can skip this property if your application is in small size.

Example

// index.js file in your React App

const React = require('react')
const ReactDOM = require('react-dom')
const { registerObserver } = require('react-perf-devtool')

const Component = require('./Component') // Some React Component

const options = {
  shouldLog: true,
  port: 8080,
  timeout: 12000 // Load the extension after 12 sec.
}

function callback(measures) {
  // do something with the measures
}

// assign the observer to the global scope, as the GC will delete it otherwise
window.observer = registerObserver(options, callback)

ReactDOM.render(<Component />, document.getElementById('root'))
// server.js
const { json } = require('micro')

module.exports = async req => {
  console.log(await json(req))
  return 200
}
// package.json

{
  "main": "server.js",
  "scripts": {
    "start-micro": "micro -p 8080"
  }
}

Schema of the measures

Below is the schema of the performance measures that are logged to the console.

{
  componentName, 
  mount: { // Mount time
    averageTimeSpentMs,
    numberOfTimes,
    totalTimeSpentMs,
  },
  render: { // Render time
    averageTimeSpentMs,
    numberOfTimes,
    totalTimeSpentMs,
  },
  update: { // Update time
    averageTimeSpentMs,
    numberOfTimes,
    totalTimeSpentMs,
  },
  unmount: { // Unmount time
    averageTimeSpentMs,
    numberOfTimes,
    totalTimeSpentMs,
  },
  totalTimeSpent, // Total time taken by the component combining all the phases
  percentTimeSpent, // Percent time
  numberOfInstances, // Number of instances of the component

  // Time taken in lifecycle hooks
  componentWillMount: {
    averageTimeSpentMs,
    numberOfTimes,
    totalTimeSpentMs,
  }
  componentDidMount: {
    averageTimeSpentMs,
    numberOfTimes,
    totalTimeSpentMs,
  }
  componentWillReceiveProps: {
    averageTimeSpentMs,
    numberOfTimes,
    totalTimeSpentMs,
  },
  shouldComponentUpdate: {
    averageTimeSpentMs,
    numberOfTimes,
    totalTimeSpentMs,
  },
  componentWillUpdate: {
    averageTimeSpentMs,
    numberOfTimes,
    totalTimeSpentMs,
  },
  componentDidUpdate: {
    averageTimeSpentMs,
    numberOfTimes,
    totalTimeSpentMs,
  },
  componentWillUnmount: {
    averageTimeSpentMs,
    numberOfTimes,
    totalTimeSpentMs,
  }
}

components

You can also inspect the performance of specific components using options through components property.

Example -

const options = {
  shouldLog: true,
  port: 3000,
  components: ['App', 'Main'] // Assuming you've these components in your project
}

function callback(measures) {
  // do something with measures
}

// assign the observer to the global scope, as the GC will delete it otherwise
window.observer = registerObserver(options, callback)

Description

Overview section

Overview section represents an overview of total time (%) taken by all the components in your application.

Results section

  • Time taken by all the components - Shows the time taken by all the components (combining all the phases).

  • Time duration for committing changes - Shows the time spent in committing changes. Read more about this here

  • Time duration for committing host effects - Shows the time spent in committing host effects i.e committing when a new tree is inserted (update) and no. of host effects (effect count in commit).

  • Time duration for calling lifecycle methods - Reports the time duration of calling lifecycle hooks and total no of methods called, when a lifecycle hook schedules a cascading update.

  • Total time

Top section

clear - The clear button clears the measures from the tables and also wipes the results.

Reload the inspected window - This button reloads the inspected window and displays the new measures.

Pending events - This indicates the pending measures (React performance data).

Components section

This section shows the time taken by a component in a phase, number of instances of a component and total time combining all the phases in ms and %

Phases

Given below are the different phases for which React measures the performance:

  • React Tree Reconciliation - In this phase, React renders the root node and creates a work in progress fiber. If there were some cascading updates while reconciling, it will pause any active measurements and will resumed them in a deferred loop. This is caused when a top-level update interrupts the previous render. If an error was thrown during the render phase then it captures the error by finding the nearest error boundary or it uses the root if there is no error boundary.

  • Commit changes - In this phase, the work that was completed is committed. Also, it checks whether the root node has any side-effect. If it has an effect then add it to the list (read more this list data structure here) or commit all the side-effects in the tree. If there is a scheduled update in the current commit, then it gives a warning about cascading update in lifecycle hook. During the commit phase, updates are scheduled in the current commit. Also, updates are scheduled if the phase/stage is not componentWillMount or componentWillReceiveProps.

  • Commit host effects - Host effects are committed whenever a new tree is inserted. With every new update that is scheduled, total host effects are calculated. This process is done in two phases, the first phase performs all the host node insertions, deletion, update and ref unmounts and the other phase performs all the lifecycle and ref callbacks.

  • Commit lifecycle - When the first pass was completed while committing the host effects, the work in progress tree became the current tree. So work in progress is current during componentDidMount/update. In this phase, all the lifecycles and ref callbacks are committed. Committing lifecycles happen as a separate pass so that all the placements, updates and deletions in the entire tree have already been invoked.

Implementation

In previous version of this devtool, performance metrics were being queried instead of listening for an event type. This required to comment the line inside the react-dom package (react-dom.development.js) so that these metrics can be captured by this tool.

Trade-offs

  • Need to update the commonjs react-dom development bundle (commenting the line)
  • 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 - log only the render and update performance of a component)

But now, with the help of Performance Observer API, an observer can be registered to listen to an event of a particular type and get the entries (performance measures). react-perf-devtool provides an API on top of the performance observer, a function that registers an observer.

const { registerObserver } = require('react-perf-devtool')

// assign the observer to the global scope, as the GC will delete it otherwise
window.observer = registerObserver()

This observer listens to the React performance measurement event. It hooks an object containing information about the events and performance measures of React components to the 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 and also the cache.

An option object and an optional callback can also be passed to registerObserver. The option object is useful when performance measures are to be logged to a console. The callback receives parsed and aggregated results (metrics) as its argument which can then be used for analyses.

Benefits

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 (not done with the API for it yet)
  • This also gives control to the developer on how to manage and inspect the measures apart from using the extension

Todos / Ideas / Improvements

  • New UI for devtool
  • Make the implementation of measures generator more concrete
  • Add support for older versions of React
  • Make the tool more comprehensible

Contributing

Read the contributing guide

License

MIT

More Repositories

1

react-imgpro

πŸ“· Image Processing Component for React
JavaScript
2,176
star
2

terminal-in-react

πŸ‘¨β€πŸ’» A component that renders a terminal
JavaScript
2,124
star
3

redocx

πŸ“„ Create word documents with React
JavaScript
1,389
star
4

Making-a-custom-React-renderer

Tutorial on how to make a custom React renderer
JavaScript
1,286
star
5

animate-components

✨ Elemental components for doing animations in React
JavaScript
909
star
6

React-Web-AR

πŸ•ΆοΈ Augmented Reality on web with React
JavaScript
571
star
7

react-color-extractor

A React component which extracts colors from an image
JavaScript
351
star
8

Python-Automation

πŸ’» These are some projects which I worked upon to automate stuffs using python
Python
246
star
9

Animated-Timeline

πŸ”₯ Create timeline and playback based animations in React
JavaScript
197
star
10

react-video-scroll

A React component to seek or control the video frame rate on scroll.
JavaScript
135
star
11

glamorous-primitives

πŸ’„ style primitive React interfaces with glamorous
JavaScript
92
star
12

react-tint

A React component that applies image processing filters to an image using Processing
JavaScript
87
star
13

react-color-tools

A set of tools as React components for working with colors 🎨
JavaScript
87
star
14

shaping-functions

Visualisation of shaping functions
JavaScript
75
star
15

linkify-markdown

πŸš€ A cli tool which automatically add references to issues, pull requests, user mentions and forks to a markdown file.
JavaScript
69
star
16

react-handy-renderer

✏️ Draw 2D primitives in sketchy style with React
JavaScript
61
star
17

generative-designs

A collection of generative design React components
JavaScript
58
star
18

stylus-in-react

πŸ’„ Style React components with Stylus
JavaScript
54
star
19

react-text-fun

React meets Blotter.js
JavaScript
52
star
20

react-marker

πŸ–οΈ Highlight keywords and add colors to your text.
JavaScript
47
star
21

generative-art-tools

Utilities for creating generative art
JavaScript
27
star
22

vscode-glamorous

πŸ€™ code snippets for glamorous
21
star
23

Elements-of-physics

Representing elements of physics using React
JavaScript
20
star
24

react-shader-canvas

A small utility function to render the shaders using React
JavaScript
20
star
25

Creating-a-pretty-printer

This is a tutorial for creating a pretty printer in JavaScript
JavaScript
13
star
26

generative-art-snippets

A collection of some useful snippets used in crafting computational art
10
star
27

glamorous-redocx

style redocx components with glamorous πŸ’„
JavaScript
10
star
28

Tidings

πŸ—žοΈ A NLP based news app powered by API.ai
JavaScript
8
star
29

pro-branch

A small package that provides helpers to manage control flow in React
JavaScript
8
star
30

lightup

πŸ’‘ A cli tool to quickly launch your react app in an effortless way.
JavaScript
8
star
31

glamorous-stylus

Use Stylus with glamorous
JavaScript
6
star
32

react-image-overlay-effect

A React component for displaying an overlay effect on an image.
TypeScript
5
star
33

component-dot-json

Create and mock stateless React components using JSON
JavaScript
5
star
34

Creating-a-JavaScript-UI-library

This is a tutorial for creating a JavaScript UI library.
5
star
35

babel-preset-hyperapp

A Babel preset for HyperApp
JavaScript
4
star
36

HyperApp-Examples

HyperApp examples
JavaScript
4
star
37

word-classes-visualiser

A small tool based on Compromise NLP to visualise the different word classes from English grammar.
JavaScript
4
star
38

Blog

πŸ“— My writings
3
star
39

algorithmic-art-sketchbook

work in progress
JavaScript
3
star
40

Learning-Processing

A curated list of resources, links and books for learning processing
JavaScript
3
star
41

glam-atom

Glamorous Snippets for Atom
3
star
42

css-to-rn

Convert css string to React Native
JavaScript
3
star
43

myspace

Blog
2
star
44

Working-with-APIs

This repository contains scripts for accessing the third party APIs using Python, JavaScript and Ruby.
Python
2
star
45

T-Box

A command line utility to manage the file uploads, downloads and sharing directly from terminal on your Dropbox.
JavaScript
2
star
46

Nitin-Blog

Welcome to my blog!
2
star
47

personal-blog

My blog
JavaScript
2
star
48

Resume

1
star
49

test-repo

1
star
50

test-draft-releaser

1
star
51

nextjs-netlify-blog-template

TypeScript
1
star
52

Escaper

A small library which provides methods to escape and unescape HTML entities.
JavaScript
1
star
53

nextjs-netlify-blog-template-nitin

1
star
54

insiderin-assignment

assignment
JavaScript
1
star
55

Project-Euler

Contains my solutions to the computational problems at https://projecteuler.net/
Python
1
star
56

nitin42

My personal repository
1
star
57

Real-Markdown

An app that let’s us view the raw markdown on one side and the converted markdown (to HTML) on the other side.
JavaScript
1
star
58

routes-getter

Walks through your routes folder and imports them to your project.
JavaScript
1
star
59

grabvatar

An amazing tool to generate cool avatars for your profile picture given an identifier.
JavaScript
1
star