Skip to content

Make it easier to properly profile with the React DevTools. #7734

Closed

Description

@kentcdodds

I wrote a blog post about how to properly profile a React App for Performance and I use a react-scripts app to demonstrate how to do it. There are a few steps in there that I'd love to make easier.

Specifically, you have to go into ./node_modules/react-scripts/config/webpack.config.js to update the webpack config to add this to resolve.alias:

'react-dom$': 'react-dom/profiling',
'scheduler/tracing': 'scheduler/tracing-profiling',

And you have to add this to the Terser options:

keep_classnames: true,
keep_fnames: true,

It's a bit of an annoying process and I think we could make it a lot easier (and hopefully encourage people to profile their apps in the process).

Describe the solution you'd like

We'd make a change here: https://github.com/facebook/create-react-app/blob/0d1775e739b091affaf8b11a85aaa435fc53ee64/packages/react-scripts/config/webpack.config.js#L302-L306

-      alias: {
+      alias: removeEmpty({
         // 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$': isEnvProductionProfile ? 'react-dom/profiling' : null,
+        'scheduler/tracing': isEnvProductionProfile ? 'scheduler/tracing-profiling' : null,
+      }),
-      },

Where removeEmpty is something like (borrowed from webpack-config-utils):

function removeEmpty(input) {
  const output = {}
  Object.keys(input).forEach(key => {
    const value = input[key]
    if (typeof value !== 'undefined') {
      output[key] = value
    }
  })
  return output
}

and isEnvProductionProfile is defined as: isEnvProduction && Boolean(process.env.PROFILE_APP).

We'd also add this right above: https://github.com/facebook/create-react-app/blob/0d1775e739b091affaf8b11a85aaa435fc53ee64/packages/react-scripts/config/webpack.config.js#L237

keep_classnames: isEnvProductionProfile,
keep_fnames: isEnvProductionProfile,

Describe alternatives you've considered

Currently the alternative is to change it manually (and if you deploy from your local build then you need to remember to remove your edits).

Additional context

I'm bringing this up because I'd love to update my blog post to simply be: "Now, run the build in profiling mode with npx cross-env PROFILE_APP=true npm run build." That would be awesome. And it would make every-day profiling much simpler as well.

Activity

  1. kentcdodds commented on Sep 25, 2019

    @kentcdodds
    ContributorAuthor

    By the way, I don't really care exactly how this is implemented. If you don't like the environment variable/removeEmpty function/etc, that's fine. I just want to make this easier.

  2. JacobMGEvans commented on Sep 25, 2019

    @JacobMGEvans
    Contributor

    Are those steps to implementing this? Could we just make a PR then?

  3. kentcdodds commented on Sep 25, 2019

    @kentcdodds
    ContributorAuthor

    I think so!

  4. jamesb3ll commented on Sep 25, 2019

    @jamesb3ll

    Instead of removeEmpty function, spread operator could be used:

    alias: {
      'react-native': 'react-native-web',
      ...(isEnvProductionProfile && {
        'react-dom$': 'react-dom/profiling',
        'scheduler/tracing': 'scheduler/tracing-profiling',
      }),
    }
    
  5. JacobMGEvans commented on Sep 26, 2019

    @JacobMGEvans
    Contributor

    Instead of removeEmpty function, spread operator could be used:

    alias: {
      'react-native': 'react-native-web',
      ...(isEnvProductionProfile && {
        'react-dom$': 'react-dom/profiling',
        'scheduler/tracing': 'scheduler/tracing-profiling',
      }),
    }
    

    Would any type safety be lost? Or would that short circuit be handling that logically equivalent?

  6. JacobMGEvans commented on Sep 26, 2019

    @JacobMGEvans
    Contributor

    I started to implement this here is the draft PR: #7737
    Currently, I have an issue with the keep_classnames and I am guessing keep_fnames might have some issues.
    Here is the current compiler error:
    yarn run v1.17.3
    $ cd packages/react-scripts && node bin/react-scripts.js build
    Creating an optimized production build...
    Failed to compile.

    Failed to minify the bundle. Error: static/js/main.b21b40a1.chunk.js from Terser
    `keep_classnames` is not a supported option
        at /Users/jacobevans/personalProjects/create-react-app/packages/react-scripts/scripts/build.js:176:23
        at finalCallback (/Users/jacobevans/personalProjects/create-react-app/node_modules/webpack/lib/Compiler.js:257:39)
        at /Users/jacobevans/personalProjects/create-react-app/node_modules/webpack/lib/Compiler.js:273:13
        at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/jacobevans/personalProjects/create-react-app/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1)
        at AsyncSeriesHook.lazyCompileHook (/Users/jacobevans/personalProjects/create-react-app/node_modules/tapable/lib/Hook.js:154:20)
        at onCompiled (/Users/jacobevans/personalProjects/create-react-app/node_modules/webpack/lib/Compiler.js:271:21)
        at /Users/jacobevans/personalProjects/create-react-app/node_modules/webpack/lib/Compiler.js:681:15
        at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/jacobevans/personalProjects/create-react-app/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1)
        at AsyncSeriesHook.lazyCompileHook (/Users/jacobevans/personalProjects/create-react-app/node_modules/tapable/lib/Hook.js:154:20)
        at /Users/jacobevans/personalProjects/create-react-app/node_modules/webpack/lib/Compiler.js:678:31
        at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/jacobevans/personalProjects/create-react-app/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1)
        at AsyncSeriesHook.lazyCompileHook (/Users/jacobevans/personalProjects/create-react-app/node_modules/tapable/lib/Hook.js:154:20)
        at /Users/jacobevans/personalProjects/create-react-app/node_modules/webpack/lib/Compilation.js:1423:35
        at AsyncSeriesHook.eval [as callAsync] (eval at create (/Users/jacobevans/personalProjects/create-react-app/node_modules/tapable/lib/HookCodeFactory.js:33:10), <anonymous>:6:1)
        at AsyncSeriesHook.lazyCompileHook (/Users/jacobevans/personalProjects/create-react-app/node_modules/tapable/lib/Hook.js:154:20)
        at /Users/jacobevans/personalProjects/create-react-app/node_modules/webpack/lib/Compilation.js:1414:32
    Read more here: https://bit.ly/CRA-build-minify
  7. kevin940726 commented on Sep 26, 2019

    @kevin940726
    Contributor

    @JacobMGEvans I left the comment in the PR :)

  8. JacobMGEvans commented on Sep 26, 2019

    @JacobMGEvans
    Contributor

    @kevin940726 Pointing out I had the keep_classnames and keep_fnames inside of the
    output: { ... } rather than outside of it in the scope of the terserOptions: { ... }

    @kentcdodds works as you expected now, I just misread your direction for that part of the implementation.

  9. kentcdodds commented on Oct 3, 2019

    @kentcdodds
    ContributorAuthor

    Huzzah!!!! Thanks @iansu! And well done @JacobMGEvans 👏

    I understand that my needs are not your deadlines, but if this could be released for my workshop by next Monday that would be awesome 😁

  10. iansu commented on Oct 3, 2019

    @iansu
    Contributor

    @kentcdodds It's released now!

  11. locked and limited conversation to collaborators on Oct 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions