facebook / create-react-app

Set up a modern web app by running one command.
https://create-react-app.dev
MIT License
102.61k stars 26.79k forks source link

Slow compilation still after upgrade to new version 4.0.1 #10154

Open dagar07 opened 3 years ago

dagar07 commented 3 years ago

This issue has been fixed in 4.0.1. https://github.com/facebook/create-react-app/releases/tag/v4.0.1

The performance is much, much better now! Thank you! ❤🎉

This issue did not fix yet, still take around 30s to 40s to recompile the changes after a small change in the files

Originally posted by @raRaRa in https://github.com/facebook/create-react-app/issues/9966#issuecomment-732064935

andrwo commented 3 years ago

I concur. I have upgraded to 4.0.1 (using Typescript 4.1.2).

Initial compile times are better.

But each time I modify a single tsx file, the diff re-"Compiling..." cycle is taking way longer than pre v4. Previously it takes around 2-3 seconds to reflect in browser, now it takes upwards of 15 seconds.

I tried with both setting in .env file FAST_REFRESH = true and false, no difference.

eek commented 3 years ago

I have the same issue. Extremely slow compile and recompile times.

I tried measuring the compile time with https://github.com/stephencookdev/speed-measure-webpack-plugin to see what's so slow.

This is my benchmark:

image

Unfortunately I couldn't run it on re-compile after a file update because apparently it breaks. Might have something to do with https://github.com/stephencookdev/speed-measure-webpack-plugin/issues/44

But, it's extremely slow lol. And also the discussions (like this - https://github.com/facebook/create-react-app/discussions/9909) aren't very helpful

ahrbil commented 3 years ago

Did you guys notice any slow build time as well? I can't even build our app on CI as it is always failing due to time out after upgrading to both v4.0.0 and v4.0.1

jamiehaywood commented 3 years ago

@ahrbil could you detail your issues some more about the CI? I encountered the same issue today. Build keeps timing out (even though it's already built the static files!): image

maxsbelt commented 3 years ago

I tried to debug my app using speed-measure-webpack-plugin (thanks @eek for suggestion) and figured out that problem is 100% (at least in my case) related to ESLintPlugin. Here some metrics:

version 3.4.4 version 4.0.1 version 4.0.1 (second run) version 4.0.1 without ESLintPlugin
Screenshot 2020-11-26 at 20 20 59 Screenshot 2020-11-26 at 20 24 34 Screenshot 2020-11-26 at 20 25 31 Screenshot 2020-11-26 at 20 26 32

You can try if it works in your case by commenting out the plugin in node_modules/react-scripts/config/webpack.config.js:

Screenshot 2020-11-26 at 20 45 21

As a temporary solution you can use react-app-rewired with such config-override:

module.exports = (config) => {
  config.plugins = config.plugins.filter(
    (plugin) => !(plugin.options && plugin.options.eslintPath)
  );
  return config;
};
ejose19 commented 3 years ago

@maxsbelt Thanks, the speeds after that change are amazing, just a couple of seconds for initial compilation and 1s for recompilation. Here's a patch for those using patch-package

diff --git a/node_modules/react-scripts/config/webpack.config.js b/node_modules/react-scripts/config/webpack.config.js
index eddca1b..954abe9 100644
--- a/node_modules/react-scripts/config/webpack.config.js
+++ b/node_modules/react-scripts/config/webpack.config.js
@@ -750,7 +750,7 @@ module.exports = function (webpackEnv) {
           // The formatter is invoked directly in WebpackDevServerUtils during development
           formatter: isEnvProduction ? typescriptFormatter : undefined,
         }),
-      new ESLintPlugin({
+      isEnvProduction && new ESLintPlugin({
         // Plugin options
         extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
         formatter: require.resolve('react-dev-utils/eslintFormatter'),
dagar07 commented 3 years ago

I tried to debug my app using speed-measure-webpack-plugin (thanks @eek for suggestion) and figured out that problem is 100% (at least in my case) related to ESLintPlugin. Here some metrics:

version 3.4.4 version 4.0.1 version 4.0.1 (second run) version 4.0.1 without ESLintPlugin Screenshot 2020-11-26 at 20 20 59 Screenshot 2020-11-26 at 20 24 34 Screenshot 2020-11-26 at 20 25 31 Screenshot 2020-11-26 at 20 26 32 You can try if it works in your case by commenting out the plugin in node_modules/react-scripts/config/webpack.config.js:

Screenshot 2020-11-26 at 20 45 21

As a temporary solution you can use react-app-rewired with such config-override:

module.exports = (config) => {
  config.plugins = config.plugins.filter(
    (plugin) => !(plugin.options && plugin.options.eslintPath)
  );
  return config;
};

Not worked for me

JanJakes commented 3 years ago

May be related to https://github.com/facebook/create-react-app/issues/10119.

ahrbil commented 3 years ago

@ahrbil could you detail your issues some more about the CI? I encountered the same issue today. Build keeps timing out (even though it's already built the static files!): image

@jamiehaywood it's the same issue we are facing too image

eek commented 3 years ago

@JanJakes that's true, the issue seems to be related to threads: false.

I've added that to the ESLintPlugin options and now it's fast compiling again.

I've tested it with overriding the config. If you have craco or react-app-rewired you can test it with:

overrideWebpackConfig: ({ webpackConfig }) => {
    webpackConfig.plugins = webpackConfig.plugins.filter(
        (plugin) => !(plugin.options && 'eslintPath' in plugin.options)
    );

    webpackConfig.plugins.unshift(new ESLintPlugin({
        // Plugin options
        extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
        formatter: require.resolve('react-dev-utils/eslintFormatter'),
        eslintPath: require.resolve('eslint'),
        context: './src',
        cache: true,

        // Setting threads to false boost compiling speed back to previous levels
        threads: false,

        // ESLint class options
        cwd: fs.realpathSync(process.cwd()),
        resolvePluginsRelativeTo: __dirname,
        baseConfig: {
            extends: [require.resolve('eslint-config-react-app/base')],
            rules: {
                'react/react-in-jsx-scope': 'error',
            },
        },
    }));

    return webpackConfig;
}

replace overrideWebpackConfig: ({ webpackConfig }) => { with module.exports = (webpackConfig) => { for react-app-rewired

cc - https://github.com/webpack-contrib/eslint-webpack-plugin/issues/50#issuecomment-732376285 cc - https://github.com/facebook/create-react-app/issues/10119

dagar07 commented 3 years ago

@eek I have done the same thing and but it's not working

eek commented 3 years ago

@eek I have done the same thing and but it's not working

@dagar07 try this:

ADD:

  "resolutions": {
    "react-scripts/eslint-webpack-plugin": "2.3.0"
  }

at the end of the package.json file and then write yarn for it to install with the proper resolution. Should work fast afterwards.

dagar07 commented 3 years ago

@eek I have done the same thing and but it's not working

@dagar07 try this:

ADD:

  "resolutions": {
    "react-scripts/eslint-webpack-plugin": "2.3.0"
  }

at the end of the package.json file and then write yarn for it to install with the proper resolution. Should work fast afterwards.

I have added yarn module and using the yarn now, but not working ... with recompile

MaximeBernard commented 3 years ago

Thanks @maxsbelt, commenting ESLintPlugin helped my compile time from 32s to 16s. My yarn start recompile time is almost instantaneous. You made my developer experience great again 😄

jamiehaywood commented 3 years ago

for anyone that is using CRA 4.0.1 in a monorepo (using lerna) - add:

  "resolutions": {
    "react-scripts/eslint-webpack-plugin": "2.3.0"
  }

to the root package.json and it should fix the slow reloading issues.

eek commented 3 years ago

for anyone that is using CRA 4.0.1 in a monorepo (using lerna) - add:

  "resolutions": {
    "react-scripts/eslint-webpack-plugin": "2.3.0"
  }

to the root package.json and it should fix the slow reloading issues.

@jamiehaywood It was fixed in eslint-webpack-plugin 2.4.1

ejose19 commented 3 years ago

@PraveenVerma17 As I'm using npm and can't pin eslint-webpack-plugin, I'm using the change stated by @eek which works correctly

diff --git a/node_modules/react-scripts/config/webpack.config.js b/node_modules/react-scripts/config/webpack.config.js
index eddca1b..8652fc3 100644
--- a/node_modules/react-scripts/config/webpack.config.js
+++ b/node_modules/react-scripts/config/webpack.config.js
@@ -757,6 +757,7 @@ module.exports = function (webpackEnv) {
         eslintPath: require.resolve('eslint'),
         context: paths.appSrc,
         cache: true,
+        threads: false,
         // ESLint class options
         cwd: paths.appPath,
         resolvePluginsRelativeTo: __dirname,
ejose19 commented 3 years ago

@PraveenVerma17 Are you using react-scripts v4.0.1?

eek commented 3 years ago

@PraveenVerma17 just delete the node_modules folder and install again, it should automatically install the latest eslint-webpack-plugin which no longer has the issue.

ejose19 commented 3 years ago

@eek Correct, there's no longer need for a patch as it works correctly on eslint-webpack-plugin v2.4.1, however if they're using npm and already had a package-lock.json it won't update the version even after deleting node_modules and installing again. @PraveenVerma17 What you need to do is, remove the patch and run npm uninstall react-scripts && npm install -D react-scripts so you actually get the latest version.

benduran commented 3 years ago

Hi folks 👋 Wanted to chime in and say that I'm glad to see there's discussion around this issue. I've recently attempted an upgrade to a few applications. Some applications build fine, but are noticeably slower. One application hangs almost indefinitely, and pegs my disk I/O at 100% usage, rendering my system nearly unusable. The last stable version of CRA3.X worked like a charm, no issues.

emersonlaurentino commented 3 years ago

using resolutions worked correctly for me, btw thanks @eek and @jamiehaywood

"resolutions": {
  "react-scripts/eslint-webpack-plugin": "2.4.1"
}
dagar07 commented 3 years ago

@eek I have updated to "eslint-webpack-plugin": "^2.4.1", but its not solve, Please help me to fix this

jarretmoses commented 3 years ago

Is there an update with this issue? 4.x is still unusable for me as compile times are way too long. Especially the initial startup. Im all up to date versioning have cleared my node modules, followed other suggestion but everything is still extremely slow.

fo-fo commented 3 years ago

Our initial startup time has gone from ~40s (react-scripts 3.4.0) to ~3m30s (react-scripts 4.0.1), a 5x increase.

EDIT: Disabling ESLintPlugin brings it down to around 1m20s, but still not very happy about it 😕 (2x increase)

andrwo commented 3 years ago

Anyone tried if the 4.0.2 update that just dropped fixes this issue?

xfournet commented 3 years ago

@andrwo yes the DISABLE_ESLINT_PLUGIN option fix my compilation speed problem (i have my own setup of eslint). See #10170

leojh commented 3 years ago

at least for us it improved start substantially. it's now back to about the same it was before CRA 4.

stclairdaniel commented 3 years ago

I'm still getting quite slow start and lint speeds on react-scripts 4.3.0, even with

"resolutions": {
  "react-scripts/eslint-webpack-plugin": "2.4.1"
}
Tiberriver256 commented 3 years ago

Resolutions resolved the issue for me on initial build time

Jayaramstarr commented 3 years ago

@JanJakes that's true, the issue seems to be related to threads: false.

I've added that to the ESLintPlugin options and now it's fast compiling again.

I've tested it with overriding the config. If you have craco or react-app-rewired you can test it with:

overrideWebpackConfig: ({ webpackConfig }) => {
    webpackConfig.plugins = webpackConfig.plugins.filter(
        (plugin) => !(plugin.options && 'eslintPath' in plugin.options)
    );

    webpackConfig.plugins.unshift(new ESLintPlugin({
        // Plugin options
        extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
        formatter: require.resolve('react-dev-utils/eslintFormatter'),
        eslintPath: require.resolve('eslint'),
        context: './src',
        cache: true,

      // Setting threads to false boost compiling speed back to previous levels
        threads: false,

        // ESLint class options
        cwd: fs.realpathSync(process.cwd()),
        resolvePluginsRelativeTo: __dirname,
        baseConfig: {
            extends: [require.resolve('eslint-config-react-app/base')],
            rules: {
                'react/react-in-jsx-scope': 'error',
            },
        },
    }));

    return webpackConfig;
}

replace overrideWebpackConfig: ({ webpackConfig }) => { with module.exports = (webpackConfig) => { for react-app-rewired

cc - webpack-contrib/eslint-webpack-plugin#50 (comment) cc - #10119

Can you tell me the file and the file path where to set this?

ivanviskovic commented 3 years ago

Also very slow build time. When i tried to debug it with speed-measure-webpack-plugin but could not find anything. Screenshot 2021-07-05 at 12 40 13

Anyone have any idea what might be the problem?

SamKirkland commented 3 years ago

Root Problem in my case

Create React App uses CaseSensitivePathsPlugin and IgnorePlugin. In my case replacing these two plugins with alternatives reduced my dev environment build time from 14 minutes to 3 minutes. I did a bit of research and it appears these two plugins account for 60-80% of the build time for other projects on github. So I figured I would leave instructions here on how to implement these changes. I would like to put together a PR for these changes, so please leave feedback and I'll make a PR if all goes well with others.

Notes about these changes

The CaseSensitivePathsPlugin is already disabled on the production build. Which means these changes mostly help the dev build. These changes worked for me. But that does not mean they will work for you. Please run the speed-measure-webpack-plugin before making these changes. Also if these changes do fix your build issues please leave a comment with before/after timings or feedback so I can put together a Pull Request.

That being said I think this change could help a few people:

Testing these changes on the largest CRA project I've contributed to (AppSmith) made the following changes.

Before (8 minutes)

image

After (2.2 minutes)

image

^ timings are averages over 3 runs

Solution

We are going to replace both the CaseSensitivePathsPlugin and IgnorePlugin plugins. To do so we need craco to make modification to CRA webpack config without ejecting.

Craco config

const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const MomentLocalesPlugin = require("moment-locales-webpack-plugin");

module.exports = {
    plugins: [
        {
            plugin: {
                overrideWebpackConfig: ({ webpackConfig }) => {
                    // remove CaseSensitivePathsPlugin (replace with tsconfig setting or eslint setting)
                    webpackConfig.plugins = webpackConfig.plugins.filter(
                        (plugin) => plugin.constructor.name !== "CaseSensitivePathsPlugin"
                    );

                    // remove IgnorePlugin
                    webpackConfig.plugins = webpackConfig.plugins.filter(
                        (plugin) => plugin.constructor.name !== "IgnorePlugin"
                    );
                    // add new ContextReplacementPlugin via moment-locales-webpack-plugin
                    webpackConfig.plugins.push(new MomentLocalesPlugin()); // exclude all locales except en

                    const smp = new SpeedMeasurePlugin({
                        outputFormat: "humanVerbose",
                        loaderTopFiles: 5,
                    });

                    return smp.wrap(webpackConfig);
                },
            }
        }
    ]
};

What is case-sensitive-paths-webpack-plugin doing?

See the code in CRA webconfig Why does this plugin exist, well looking at the github history it adds checks for NTFS (windows) vs. APFS (mac) file systems. If all your machines are on a single OS, including build servers you could remove this plugin.

However I want to keep it around just in case someone on my team develops on another OS. One option is to use ESLint instead with the eslint-plugin-import plugin and its caseSensitive option. Or if you are using typescript remove the plugin and enable the tsconfig option forceConsistentCasingInFileNames which will do the same thing in a fraction of the time - this is what I did. Note: I need to do some more testing to verify ESLint/Typescript are doing the equivalent checks. One concern I have is these alternatives are not recursively checking the dir tree.

What is IgnorePlugin doing?

See the code in CRA webconfig This configuration of the IgnorePlugin helps reduce the bundle size when using moment js. However swapping it out with the newer ContextReplacementPlugin improves performance dramatically.

Maintainer for Performance?

@gaearon / @Timer / @ianschmitz Any thoughts on adding a maintainer for performance related issues. As you know perf issues are normally the last priority so there might be some value in a dedicated perf maintainer. (related https://github.com/facebook/create-react-app/issues/8096#issuecomment-751894155)

FezVrasta commented 3 years ago

I just tested the above suggestions and I couldn't observe any performance difference at all in my setup. I'm on macOS Big Sur on a Late 2014 iMac 5k (3.5 GHz Quad-Core Intel Core i5)

What I noticed is that InjectManifest plugin takes almost 7 seconds to run. It seems a lot, maybe something can be done to optimize it.

Mathieuu commented 2 years ago

For our project, the performance gain is dramatic. I followed SamKirkland comment and simply filtered CaseSensitivePathsPlugin and IgnorePlugin plugin. (Macbook pro 2019 i9 8core with 32GB of ram, yarn running directly in mac os)

Before/After

Screen Shot 2022-01-05 at 6 06 03 PM Screen Shot 2022-01-05 at 6 05 50 PM
rkhaslarov commented 2 years ago

In out case it's babel-loader SMP ⏱ General output time took 71,230 ms

SMP ⏱ Loaders @pmmmwh/react-refresh-webpack-plugin, and babel-loader took 58,561 ms

OR even

@pmmmwh/react-refresh-webpack-plugin, and babel-loader took 1,062,270 ms

did anyone faced the issue?

suraj-adewale commented 2 years ago

Hi everyone, I had similar experience, however I was able to fix it with following steps:

  1. I create a new react app. npx create-react-app my-app
  2. I tested npm start and it was running faster.
  3. I now compared package.json of my-app with my existing project
  4. I updated package.json of my exiting project(slow) with "react": "^18.1.0", "react-dom": "^18.1.0", "react-scripts": "5.0.1",
  5. Then npm install. Done. Try this and let me hear your feedback
jonnycbw commented 2 years ago

@suraj-adewale

Hi everyone,

I had similar experience, however I was able to fix it with following steps:

  1. I create a new react app. npx create-react-app my-app

  2. I tested npm start and it was running faster.

  3. I now compared package.json of my-app with my existing project

  4. I updated package.json of my exiting project(slow) with "react": "^18.1.0", "react-dom": "^18.1.0", "react-scripts": "5.0.1",

  5. Then npm install. Done. Try this and let me hear your feedback

Unfortunately this didn't work for me, we ended up regressing back to react-scripts 3.4.3, where it's still slow but not as slow as 4.0.1 or 5.0.1. I'm gonna give the craco solution a try to see if that helps at all.

In our case we have multiple packages but not in a monorepo, just yarn linked. We're not fussed so much about build times but more about recompile time after making changes (hmr)