Instantly share code, notes, and snippets.

@bvaughn /index.md
Last active Feb 20, 2019

Embed
What would you like to do?
How to use profiling in production mode for react-dom

React recently introduced an experimental profiler API. This page gives instructions on how to use this API in a production release of your app.

Table of Contents

Profiling in production

React DOM automatically supports profiling in development mode for v16.5+, but since profiling adds some small additional overhead it is opt-in for production mode. This gist explains how to opt-in.

Create React App

Enabling profiling permanently

At the moment, the only way to permanently enable production profiling in CRA apps is to eject. Then you can follow the instructions below and apply these changes to config/webpack.config.prod.js in your app folder.

However, you can also enable profiling temporarily without ejecting.

Enabling profiling temporarily

If you only want to profile the application locally in production mode, you can do this by editing node_modules directly.

Follow the instructions below, and apply them to node_modules/react-scripts/config/webpack.config.prod.js. Then you can run yarn build or npm run build to get a profiling build. Note that your changes would be temporary and will not persist between re-runs of your package manager.

Changing the Webpack config

To enable profiling in production mode, modify Webpack configuration file (config/webpack.config.prod.js) as shown below.

react-dom@^16.6.0 / scheduler@^0.10.0

module.exports = {
  // ...
  resolve: {
    // ...
    alias: {
      // ...
      'react-dom$': 'react-dom/profiling',
      'scheduler/tracing': 'scheduler/tracing-profiling',
    },
    // ...
  },
  // ...
};

Note that if you're using a version of react/react-dom that's less than 16.6, you should refer to this earlier revision of the documentation instead.

Note that if you're using the schedule package v0.3.0-v0.4.0 you should refer to this earlier revision of the documentation instead.

Optional: Disabling mangling for local profiling

When profiling locally, you might want to disable function name mangling so that you can see the component names in the profiler. Note that this will significantly increase your bundle size so only do this during local development! To do this, find the mangle option for UglifyJSPlugin in the config, and set it to false. Don't forget to undo your changes before a real deployment.

Webpack 4

If you are using Webpack 4 to bundle your apps, add the following import aliases to your production config:

react-dom@^16.6.0 / scheduler@^0.10.0

module.exports = {
  //...
  resolve: {
    alias: {
      'react-dom$': 'react-dom/profiling',
      'scheduler/tracing': 'scheduler/tracing-profiling',
    }
  }
};

Note that if you're using a version of react/react-dom that's less than 16.6, you should refer to this earlier revision of the documentation instead.

Note that if you're using the schedule package v0.3.0-v0.4.0 you should refer to this earlier revision of the documentation instead.

Optional: Disabling mangling for local profiling

When profiling locally, you might want to disable function name mangling so that you can see the component names in the profiler. Note that this will significantly increase your bundle size so only do this during local development! To do this, find the mangle option for UglifyJSPlugin in the config, and set it to false. Don't forget to undo your changes before a real deployment.

Troubleshooting

Tracing broke after an NPM update

Both your application and react-dom need to use the same scheduler version in order for tracing to work. NPM may install multiple copies if the versions don't match, in which case your application will end up tracing interactions with a difference package than react-dom reads them from.

The safest way to ensure that this does not happen is to copy the exact scheduler version that react-dom specifies as a dependency.

Fixing this with NPM

For example, assuming you are using react-dom version 16.5.0 you can find which version of scheduler to use by running:

➜ npm view react-dom@16.6.0

dependencies:
loose-envify: ^1.1.0  object-assign: ^4.1.1 prop-types: ^15.6.2   scheduler: ^0.10.0

The above output shows that react-dom@16.6.0 depends on scheduler@^0.10.0, so your application code will also want to use that exact version.

If you're not sure if mismatching versions are installed, you can use npm ls scheduler to check:

➜ npm ls scheduler
├─┬ react@16.6.0
│ └── scheduler@0.10.0 
├─┬ react-dom@16.6.0
│ └── scheduler@0.10.0 
└── scheduler@0.9.0 

In the above example react-dom and my application are depending on different versions of scheduler. This will result in multiple copies of the package being installed (one in node_modules/scheduler and another in node_modules/react-dom/node_modules/scheduler).

You can fix this by updating your app to use the exact version react-dom is using:

➜  npm i scheduler@^0.10.0
➜  npm ls scheduler       
├─┬ react@16.6.0
│ └── scheduler@0.10.0 
├─┬ react-dom@16.6.0
│ └── scheduler@0.10.0 
└── scheduler@0.10.0 

Fixing this with Yarn

Yarn users can check to see if mismatching versions are installed using yarn why:

➜  yarn why scheduler
[1/4] 🤔  Why do we have the module "scheduler"...?
[2/4] 🚚  Initialising dependency graph...
[3/4] 🔍  Finding dependency...
[4/4] 🚡  Calculating file sizes...
=> Found "scheduler@0.9.0"
info This module exists because it's specified in "dependencies".
=> Found "react#scheduler@0.10.0"
info This module exists because "react" depends on it.
=> Found "react-dom#scheduler@0.10.0"
info This module exists because "react-dom" depends on it.
✨  Done in 0.09s.

You can fix this by updating your app to use the exact version react-dom is using:

➜  yarn add scheduler@^0.10.0
➜  yarn why scheduler
[1/4] 🤔  Why do we have the module "scheduler"...?
[2/4] 🚚  Initialising dependency graph...
[3/4] 🔍  Finding dependency...
[4/4] 🚡  Calculating file sizes...
=> Found "scheduler@0.10.0"
info Reasons this module exists
   - Specified in "dependencies"
   - Hoisted from "react#scheduler"
   - Hoisted from "react-dom#scheduler"
✨  Done in 0.09s.
@markerikson

This comment has been minimized.

Copy link

markerikson commented Sep 22, 2018

With the changes in React 16.5.2, looks like all references to tracking should be replaced with tracing, like aliasing 'schedule/tracing': 'schedule/tracing-profiling'.

@monkindey

This comment has been minimized.

Copy link

monkindey commented Oct 24, 2018

Because of facebook/react#13683 (comment) . Should we update webpack config?

module.exports = {
  //...
  resolve: {
    alias: {
      'react-dom': 'react-dom/profiling',
      'scheduler/tracing': 'scheduler/tracing-profiling',
    }
  }
};
@bvaughn

This comment has been minimized.

Copy link
Owner Author

bvaughn commented Oct 24, 2018

This gist has been updated for 16.6~

@sky0014

This comment has been minimized.

Copy link

sky0014 commented Oct 25, 2018

Will this profiling degrades performance?

@bvaughn

This comment has been minimized.

Copy link
Owner Author

bvaughn commented Oct 27, 2018

@sky0014 Using the profiler will have some impact on performance, which is why we don't enable it in the production build by default. So far from what we've observed, the impact is minimal though. (This feature was carefully implemented to minimize the impact.)

@reccanti

This comment has been minimized.

Copy link

reccanti commented Dec 11, 2018

@bvaughn To clarify, does this only have a performance impact when you're profiling? Or is that performance impact always there?

@H-KE

This comment has been minimized.

Copy link

H-KE commented Dec 13, 2018

This alias ends up conflicting with my build further downstream

ERROR in ./node_modules/react_ujs/react_ujs/index.js
Module not found: Error: Can't resolve 'react-dom/server'

Is there another way to enable the profiler in prod?

@bvaughn

This comment has been minimized.

Copy link
Owner Author

bvaughn commented Dec 28, 2018

@H-KE You might need to specify a separate alias for react-dom/server in that case.

@jrnail23

This comment has been minimized.

Copy link

jrnail23 commented Jan 28, 2019

@bvaughn, I'm not having any luck with disabling mangling in my webpack (v3) UglifyJs Plugin... should that work independently of the React devTools profiler (i.e., should it retain friendly function names when just doing regular chrome devtools profiling)?

@OliverJAsh

This comment has been minimized.

Copy link

OliverJAsh commented Jan 29, 2019

@bvaughn I'm also having this issue:

Module not found: Error: Can't resolve 'react-dom/server'

Please can you clarify what you mean by the following?

You might need to specify a separate alias for react-dom/server in that case.

I tried the following:

 module.exports = {
   //...
   resolve: {
     alias: {
       'react-dom': 'react-dom/profiling',
+      'react-dom/server': 'react-dom/profiling',
       'scheduler/tracing': 'scheduler/tracing-profiling',
     }
   }
 };

But unfortunately this doesn't seem to help.

My workaround was to comment out the part of our app where we use react-dom/server for renderToStaticMarkup on the client-side (which we use to display some HTML in a textarea), but that won't be possible for everyone.

/cc @H-KE

Re. reactjs/react-rails#955

@gaearon

This comment has been minimized.

Copy link

gaearon commented Jan 29, 2019

There’s no server profiling entry point. I think what’s happening is webpack tries to follow the first alias and so you end up in react-dom/profiling/server (which isn’t a thing).

Have you tried to set a second alias from react-dom/profiling/server to react-dom/server? Maybe that could help.

Better yet, maybe webpack has syntax for an exact match? Like react-dom$. Maybe that would prevent partial matches.

@OliverJAsh

This comment has been minimized.

Copy link

OliverJAsh commented Jan 29, 2019

@gaearon

Better yet, maybe webpack has syntax for an exact match? Like react-dom$. Maybe that would prevent partial matches.

That did the trick!

 module.exports = {
   //...
   resolve: {
     alias: {
-      'react-dom': 'react-dom/profiling',
+      'react-dom$': 'react-dom/profiling',
       'scheduler/tracing': 'scheduler/tracing-profiling',
     }
   }
 };
@bvaughn

This comment has been minimized.

Copy link
Owner Author

bvaughn commented Jan 30, 2019

That's great to learn, @OliverJAsh! I've updated the gist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment