{"id":13394335,"url":"https://github.com/nitin42/react-perf-devtool","last_synced_at":"2025-05-15T13:07:18.813Z","repository":{"id":40003114,"uuid":"114108768","full_name":"nitin42/react-perf-devtool","owner":"nitin42","description":"A browser developer tool extension to inspect performance of React components.","archived":false,"fork":false,"pushed_at":"2022-12-07T09:16:19.000Z","size":3767,"stargazers_count":2321,"open_issues_count":30,"forks_count":53,"subscribers_count":23,"default_branch":"master","last_synced_at":"2025-04-22T03:30:54.300Z","etag":null,"topics":["chrome-extension","devtool","performance","profiling","react","web"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nitin42.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-12-13T10:45:06.000Z","updated_at":"2025-04-07T05:42:22.000Z","dependencies_parsed_at":"2023-01-24T16:30:58.674Z","dependency_job_id":null,"html_url":"https://github.com/nitin42/react-perf-devtool","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitin42%2Freact-perf-devtool","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitin42%2Freact-perf-devtool/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitin42%2Freact-perf-devtool/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nitin42%2Freact-perf-devtool/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nitin42","download_url":"https://codeload.github.com/nitin42/react-perf-devtool/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254346624,"owners_count":22055808,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chrome-extension","devtool","performance","profiling","react","web"],"created_at":"2024-07-30T17:01:16.348Z","updated_at":"2025-05-15T13:07:13.803Z","avatar_url":"https://github.com/nitin42.png","language":"JavaScript","readme":"**Looking for maintainers**\n\n# React Performance Devtool\n\n[![Build Status](https://travis-ci.org/nitin42/react-perf-devtool.svg?branch=master)](https://travis-ci.org/nitin42/react-perf-devtool)\n![Release Status](https://img.shields.io/badge/status-stable-brightgreen.svg)\n![Author](https://img.shields.io/badge/author-Nitin%20Tulswani-lightgrey.svg)\n![current-version](https://img.shields.io/badge/version-3.1.8-blue.svg)\n![extension](https://img.shields.io/badge/extension-5.3-ff69b4.svg)\n[![npm downloads](https://img.shields.io/npm/dt/react-perf-devtool.svg)](https://www.npmjs.com/package/react-perf-devtool)\n\n\u003e A devtool for inspecting the performance of React Components\n\n\u003cbr/\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://i.gyazo.com/332f573872d396e4f665d58e491a8ccd.png\"\u003e\n\u003c/p\u003e\n\n\u003cbr/\u003e\n\n## Table of contents\n\n* [Introduction](#introduction)\n\n* [Demo](#demo)\n  * [Browser extension](#browser-extension)\n  * [Log the measures to console](#log-the-measures-to-a-console)\n\n* [Uses](#uses)\n\n* [Install](#install)\n\n* [Usage](#usage)\n  * [Using the browser extension](#using-the-browser-extension)\n  * [Printing the measures to console](#printing-the-measures-to-the-console)\n\n* [Description](#description)\n\n* [Phases](#phases)\n\n* [Implementation](#implementation)\n\n* [Contributing](#contributing)\n\n* [License](#license)\n\n\n## Introduction\n\n**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.\n\nAlong with the browser extension, the measures can also be inspected in a console. See the [usage](#usage) section for more details.\n\nThis project started with a purpose of extending the work done by [Will Chen](https://github.com/wwwillchen) on a proposal for React performance table. You can read more about it [here](https://github.com/facebook/react-devtools/issues/801#issuecomment-350919145).\n\n## Demo\n\n### Browser extension\n\nA demo of the extension being used to examine the performance of React components on my website.\n\n\u003cimg src=\"http://g.recordit.co/m8Yv1RTR6v.gif\"\u003e\n\n### Log the measures to a console\n\nPerformance measures can also be logged to a console. With every re-render, measures are updated and logged to the console.\n\n\u003cimg src=\"http://g.recordit.co/YX44uaVr3I.gif\"\u003e\n\n## Uses\n\n* Remove or unmount the component instances which are not being used.\n\n* Inspect what is blocking or taking more time after an operation has been started.\n\n* Examine the table and see for which components, you need to write [shouldComponentUpdate](https://reactjs.org/docs/react-component.html#shouldcomponentupdate) lifecycle hook.\n\n* Examine which components are taking more time to load.\n\n## Install\n\nTo use this devtool, you'll need to install a npm module which will register a listener (read more about this in [usage](#usage) section) and the browser extension.\n\n**Installing the extension**\n\nThe below extensions represent the current stable release.\n\n* [Chrome extension](https://chrome.google.com/webstore/detail/react-performance-devtool/fcombecpigkkfcbfaeikoeegkmkjfbfm)\n* [Firefox extension](https://addons.mozilla.org/en-US/firefox/addon/nitin-tulswani/)\n* **Standalone app coming soon**\n\n**Installing the npm module**\n\n```\nnpm install react-perf-devtool\n```\n\nA `umd` build is also available via [unpkg](https://www.unpkg.com)\n\n```js\n\u003cscript crossorigin src=\"https://unpkg.com/react-perf-devtool@3.0.8-beta/lib/npm/hook.js\"\u003e\u003c/script\u003e\n```\n\n\u003e This extension and package also depends on react. Please make sure you have those installed as well.\n\n\u003e Note - The npm module is important and required to use the devtool. So make sure you've installed it before using the browser extension.\n\n## Usage\n\nThis section of the documentation explain the usage of devtool and the API for registering an observer in a React app.\n\n### Browser Compatibility\n`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](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver#Browser_compatibility).\n\n### Using the browser extension\n\nTo 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.\n\n**Register observer**\n\nRegistering an observer is very simple and is only one function call away. Let's see how!\n\n```js\nconst { registerObserver } = require('react-perf-devtool')\n\n// assign the observer to the global scope, as the GC will delete it otherwise\nwindow.observer = registerObserver()\n```\n\nYou can place this code inside your `index.js` file (recommended) or any other file in your app.\n\n\u003e 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.\n\nRegistering an observer hooks an object containing information about the **events** and **performance measures** of React components to the\n[window](https://developer.mozilla.org/en-US/docs/Web/API/Window/window) object, which can then be accessed inside the inspected window using [eval()](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/devtools.inspectedWindow/eval).\n\nWith every re-render, this object is updated with new measures and events count.\nThe extension takes care of clearing up the memory and also the cache.\n\nYou can also pass an **`option`** object and an optional **`callback`** which receives an argument containing the parsed and aggregated measures\n\n**Using the callback**\n\nAn optional callback can also be passed to `registerObserver` which receives parsed measures as its argument.\n\nYou 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](https://developers.google.com/web/updates/2017/06/user-centric-performance-metrics).\n\nExample -\n\n```js\nconst { registerObserver } = require('react-perf-devtool')\n\nfunction callback(measures) {\n  // do something with the measures\n}\n\n// assign the observer to the global scope, as the GC will delete it otherwise\nwindow.observer = registerObserver({}, callback)\n```\n\nAfter you've registered the observer, start your local development server and go to `http://localhost:3000/`.\n\n\u003e Note - This extension works only for React 16 or above versions of it.\n\nAfter you've installed the extension successfully, you'll see a tab called **React Performance** in Chrome Developer Tools.\n\n\u003cimg src=\"./art/tab.png\"\u003e\n\n### Printing the measures to the console\n\nThe 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](https://github.com/zeit/micro) by [Zeit](https://zeit.co/) which is a HTTP microservice.\n\n```\nnpm install --save micro\n```\n\n\nYou can pass an **option** object as an argument to `registerObserver` to enable logging and setting up a port number.\n\n**Using the option object**\n\n```js\n{\n  shouldLog: boolean, // default value: false\n  port: number // default value: 8080\n  timeout: number // default value: 2000\n}\n```\n\nYou can pass three properties to the **`option`** object, `shouldLog` and `port`.\n\n* `shouldLog` - It takes a **boolean** value. If set to true, measures will be logged to the console.\n\n* `port` - Port number for the server where the measures will be send\n\n* `timeout` - A timeout value to defer the initialisation of the extension.\n\nIf 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.\n\n**Example**\n\n```js\n// index.js file in your React App\n\nconst React = require('react')\nconst ReactDOM = require('react-dom')\nconst { registerObserver } = require('react-perf-devtool')\n\nconst Component = require('./Component') // Some React Component\n\nconst options = {\n  shouldLog: true,\n  port: 8080,\n  timeout: 12000 // Load the extension after 12 sec.\n}\n\nfunction callback(measures) {\n  // do something with the measures\n}\n\n// assign the observer to the global scope, as the GC will delete it otherwise\nwindow.observer = registerObserver(options, callback)\n\nReactDOM.render(\u003cComponent /\u003e, document.getElementById('root'))\n```\n\n```js\n// server.js\nconst { json } = require('micro')\n\nmodule.exports = async req =\u003e {\n  console.log(await json(req))\n  return 200\n}\n```\n\n```js\n// package.json\n\n{\n  \"main\": \"server.js\",\n  \"scripts\": {\n    \"start-micro\": \"micro -p 8080\"\n  }\n}\n\n```\n\n**Schema of the measures**\n\nBelow is the schema of the performance measures that are logged to the console.\n\n```js\n{\n  componentName, \n  mount: { // Mount time\n    averageTimeSpentMs,\n    numberOfTimes,\n    totalTimeSpentMs,\n  },\n  render: { // Render time\n    averageTimeSpentMs,\n    numberOfTimes,\n    totalTimeSpentMs,\n  },\n  update: { // Update time\n    averageTimeSpentMs,\n    numberOfTimes,\n    totalTimeSpentMs,\n  },\n  unmount: { // Unmount time\n    averageTimeSpentMs,\n    numberOfTimes,\n    totalTimeSpentMs,\n  },\n  totalTimeSpent, // Total time taken by the component combining all the phases\n  percentTimeSpent, // Percent time\n  numberOfInstances, // Number of instances of the component\n\n  // Time taken in lifecycle hooks\n  componentWillMount: {\n    averageTimeSpentMs,\n    numberOfTimes,\n    totalTimeSpentMs,\n  }\n  componentDidMount: {\n    averageTimeSpentMs,\n    numberOfTimes,\n    totalTimeSpentMs,\n  }\n  componentWillReceiveProps: {\n    averageTimeSpentMs,\n    numberOfTimes,\n    totalTimeSpentMs,\n  },\n  shouldComponentUpdate: {\n    averageTimeSpentMs,\n    numberOfTimes,\n    totalTimeSpentMs,\n  },\n  componentWillUpdate: {\n    averageTimeSpentMs,\n    numberOfTimes,\n    totalTimeSpentMs,\n  },\n  componentDidUpdate: {\n    averageTimeSpentMs,\n    numberOfTimes,\n    totalTimeSpentMs,\n  },\n  componentWillUnmount: {\n    averageTimeSpentMs,\n    numberOfTimes,\n    totalTimeSpentMs,\n  }\n}\n```\n\n**components**\n\nYou can also inspect the performance of specific components using options through **`components`** property.\n\n\u003cimg src=\"http://g.recordit.co/sAQGSOrCA7.gif\"\u003e\n\nExample -\n\n```js\nconst options = {\n  shouldLog: true,\n  port: 3000,\n  components: ['App', 'Main'] // Assuming you've these components in your project\n}\n\nfunction callback(measures) {\n  // do something with measures\n}\n\n// assign the observer to the global scope, as the GC will delete it otherwise\nwindow.observer = registerObserver(options, callback)\n```\n\n## Description\n\n### Overview section\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://i.gyazo.com/bae8420649749a5be0a2a7e589cdbc65.png\"\u003e\n\u003c/p\u003e\n\nOverview section represents an overview of total time (%) taken by all the components in your application.\n\n### Results section\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://i.gyazo.com/74a96461182539f9866db630ab645719.png\"\u003e\n\u003c/p\u003e\n\n* Time taken by all the components - Shows the time taken by all the components (combining all the phases).\n\n* Time duration for committing changes - Shows the time spent in committing changes. Read more about this [here]()\n\n* 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).\n\n* 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.\n\n* Total time\n\n### Top section\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://i.gyazo.com/3728c55035bdcdc40b68919fe095e549.png\" /\u003e\n\u003c/p\u003e\n\n**clear** - The clear button clears the measures from the tables and also wipes the results.\n\n**Reload the inspected window** - This button reloads the inspected window and displays the new measures.\n\n**Pending events** - This indicates the pending measures (React performance data).\n\n\n### Components section\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://i.gyazo.com/ac983b28ac614fb13d980ae681ffd049.png\"\u003e\n\u003c/p\u003e\n\nThis 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 **%**\n\n## Phases\n\nGiven below are the different phases for which React measures the performance:\n\n* **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.\n\n* **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](https://github.com/nitin42/Making-a-custom-React-renderer/blob/master/part-one.md)) 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](https://reactjs.org/docs/react-component.html#componentwillmount) or [componentWillReceiveProps](https://reactjs.org/docs/react-component.html#componentwillreceiveprops).\n\n* **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.\n\n* **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**.\n\n## Implementation\n\nIn 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.\n\n### Trade-offs\n  * Need to update the commonjs react-dom development bundle (commenting the line)\n  * No way of sending the measures from the app frame to the console\n  * Need to query measures rather than listening to an event once\n  * 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)\n\nBut now, with the help of [Performance Observer](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver) 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.\n\n```js\nconst { registerObserver } = require('react-perf-devtool')\n\n// assign the observer to the global scope, as the GC will delete it otherwise\nwindow.observer = registerObserver()\n```\n\nThis observer listens to the React performance measurement event.\nIt 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().\n\nWith 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.\n\nAn `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.\n### Benefits\n\nCalculating and aggregating the results happens inside the app frame and not in the devtool. It has its own benefits.\n  * These measures can be send to a server for analyses\n  * Measures can be logged to a console\n  * Particular measures can be inspected in the console with the help of configuration object (not done with the API for it yet)\n  * This also gives control to the developer on how to manage and inspect the measures apart from using the extension\n\n## Todos / Ideas / Improvements\n\n- [x] New UI for devtool\n- [x] Make the implementation of measures generator more concrete\n- [ ] Add support for older versions of React\n- [x] Make the tool more comprehensible\n\n## Contributing\n\n[Read the contributing guide](./CONTRIBUTING.md)\n\n## License\n\nMIT\n","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnitin42%2Freact-perf-devtool","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnitin42%2Freact-perf-devtool","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnitin42%2Freact-perf-devtool/lists"}