No translations available.Add translation
The React DevToolsis an amazing piece of software and is available as a browser extension forChrome,Firefox, andis capable of being wired up to work with React app's anywhere.
One of the coolest features of the React DevTools is its profiling capabilities.There's a lot to the profiler, and we're not going to get into it all in thispost, but I thought I'd show you how you can get started using the ReactProfiler and avoid a common pitfall people run into when profiling theirapplications.
I'm going to be working withmy bookshelf app which does a goodjob of walking the line between practical enough to be "real world" but simpleenough to not require a lot of domain specific knowledge to understand. Feelfree to follow along if you'd like, or (even better) follow along in your ownproject.
Install the Extension
First step is to make sure you install the React DevTools extension for thebrowser you're using. I'm using Chrome, so I installed itin the Chrome WebStore.If it's not appearing after you install the extension, you may need to closeyour browser DevTools panel and open them again.
Start the app
The bookshelf app uses react-scripts
(thanks to create-react-app
), so afteryou've installed the project locally, run npm run start
to get the developmentserver running. This will pull up the app in your browser athttp://localhost:3000
:
Start a profiling session
Open the browser developer tools by right clicking anywhere on the page andclicking "Inspect." Then select the "⚛ Profiler" tab. This is the React DevToolsprofiler and you can now click the little blue circle to "Start profiling" theapplication.
From here go ahead and interact with the app a bit. I'm going to register for anew account. Then click the little red circle to "Stop profiling."
Explore the profiling data
From here you've got a few options for exploring the data that the DevToolscollected while you interacted with the app. The default view is the "Flamegraphchart", and there's also the "Ranked chart." Here's what the "Flamegraph chart"looks like (if you want to see the "Ranked chart," you'll have to do thisyourself 😜):
We can dive into analyzing this stuff in another post.
Pitfall: measuring development mode
I want to call out a serious pitfall that you need to avoid when doingperformance measurements like profiling. Right now we're measuring how our appperforms in development mode. If you've been using React for a while, you'relikely well aware that it ships with a lot of development-time warnings to helpguide you away from problematic code and practices. This is one of the things Ilove most about React, but that comes at a (often significant) performance cost.
Because of this, your performance measurements are tainted by React'sdevelopment-time-only code (something your users shouldn't ever be running).
So if you want to get an accurate measurement of your app's productionperformance, you should be sure to do your measurements on the productionversion of your code (the code that your end-users will be using).
Build and measure the production app
So let's run the optimized production build with npm run build
. Next we'll runnpx serve -s build
to serve up the built version of the app on an HTTP server.That should start the app on port 5000. So let's pull that up and start aprofiling session on that... Wait! Oh no! What's this?
Profiling not supported.
Profiling support requires either a development or production-profiling buildof React v16.5+.
Learn more at fb.me/react-profiling.
As it turns out, React has code in it that's specific to profiling and in theinterest of making your app as fast as possible, they actually remove that codefrom the production build of React. Thanks React! Except now what do we do?Well, I guess we could go to the linked gist by Brian! Or you could continuereading and I'll show you what to do.
NOTE: If you're using create-react-app with react-scripts@>=3.2.0
then youcan simply run npx react-scripts build --profile
and it will do all this stufffor you(thanks to Jacob) andyou can skip to the next pitfall. Otherwise, please read on.
Update the webpack config for production-profiling
As noted in the message, there's a production build of React that removes mostof the development-time helpful code, but leaves the profiling code intact. It'sstill a tiny bit slower, but it gives us the best idea of how our components areperforming in a production environment.
There are a few ways to go about this, but the simplest is to update the webpackconfiguration to alias any import of certain modules to the profiling version ofthat module. There are two such modules:
react-dom
->react-dom/profiling
scheduler/tracing
->scheduler/tracing-profiling
Both of these are React packages and need special code for the profiler to work.
How you go about updating your webpack configuration will vary based on whatframework you're using (create-react-app, next.js, gatsby.js, or your own withraw webpack). In our case, we're using create-react-app and there's not anofficially supported way to extend or modify the webpack configuration. Luckilyfor us, this is only something we want to do locally, so we're going to do alittle spelunking in our node_modules.
So, if you're using react-scripts@3.1.1
(or somewhere around there), then youcan open the webpack config here:./node_modules/react-scripts/config/webpack.config.js
Then locate the code that looks like this and add the noted lines:
// ... config ...resolve: { // ... config ... alias: { // Support React Native Web // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ 'react-native': 'react-native-web', 'react-dom$': 'react-dom/profiling', 'scheduler/tracing': 'scheduler/tracing-profiling', }, // ... more config ...}// ... more config ...
Profile the production-profiling build
Great, now run npm run build
, then npx serve -s build
and let's profile theapp again! I'll follow the same registration steps I did last time. Here's whatI came out with:
Nice! You'll notice that this is the same interaction as the last time (it'srendering the page after registration) and we went from 13.7ms to 6.5ms. Niceimprovement!
But uh oh, what's this Anonymous
component thing all over the place? And we'vegot a component called ee
another called Z
? Huh? What's going on here? Well,because we're building our app for production, we're minifying our code to makeit faster to load/parse which is a good thing for our end-users, but a bad thingfor our performance measuring because it's hard for us to know which of thesecomponents is the culprit of our performance problems.
Disable function name mangling
React knows what to call your components based on the name
property of thecomponent:
function AwesomeAppComponent() { return <div>Awesome</div>}console.log(AwesomeAppComponent.name) // <-- logs "AwesomeAppComponent"class LessAwesomeAppComponent extends React.Component { render() { return <div>Less Awesome</div> }}console.log(LessAwesomeAppComponent.name) // <-- logs "LessAwesomeAppComponent"
However, when we build our code with an "uglifier" or a "minifier," the toolchanges those names in a way that makes our code work the same as it did before,but reduce the filesize of our production JavaScript file which improvesperformance:
function a() { return <div>Awesome</div>}console.log(a.name) // <-- logs "a"class b extends React.Component { render() { return <div>Less Awesome</div> }}console.log(b.name) // <-- logs "b"
This is why we're seeing these funny names in our performance measurements. Sowe need to disable this mangling feature.
Create React App uses a tool called Terser viaterser-webpack-plugin
to do the minification, so we simply need to update the configuration topreserve the function and class names.
So in that same webpack configuration file, scroll down to where the plugin isconfigured and modify it like this:
// ... some config ...new TerserPlugin({ terserOptions: { // ... some other config ... mangle: { safari10: true, }, keep_classnames: true, keep_fnames: true, // ... some more config ... }, // ... even more config ...})
With keep_classnames
and keep_fnames
configured to true
, now let's trybuilding our app code and running a profiling session once more!
Most excellent! Now we've got a profile session showing us the names of all ofour components and they're running using code that resembles the code ourend-users will be running much more closely!
Pitfall: Profiling with a fast computer
I guarantee you that most of you reading this right now are developing your appwith a device that's way more powerful than most people using the app. There'sno substitute for trying your app on the devices that users will be using. Thatsaid, you can get a much better idea of the actual performance of your app ifyou throttle your CPU to simulate the experience of some users of your app.
So let's do that. Click on the Chrome DevTools "Performance" tab, then on thegear icon to show settings, then on the CPU option, select "6x slowdown."
Now do the whole thing again, and checkout the difference:
Phew! 31.8ms! That's quite the slow-down! Learn more about the impact of thattime on the user's experience in this blog post titledRendering Performance.This may be something worth looking into! But we'll save that for another blogpost 😉
Conclusion
We've only covered what you need to do to get started properly profiling a Reactapp, but hopefully you've learned enough to try it out on your own app and startexploring the performance implications of your app.
Also, if you'd like to dive a little further into the React DevTools,this blog post on the react blog can help.
Good luck!