parcel-bundler / parcel

The zero configuration build tool for the web. šŸ“¦šŸš€
https://parceljs.org
MIT License
43.28k stars 2.26k forks source link

Slow hot reload builds in Parcel v2 #5122

Closed elliottkember closed 1 year ago

elliottkember commented 3 years ago

šŸ› bug report

Hi all! Loving Parcel. Very excited about Parcel 2.

My Parcel 1 app is hot-reloading very slowly in Parcel 2. The reason I'm upgrading is that Parcel 1 sits at about 100-110% CPU usage even when not compiling my app. Parcel 2 doesn't do this at all (yay) but compilation time for hot module reloads has gone from 200ms to 4.0s (oh no).

We have a fairly big application, lots of files and modules, but nothing that I would consider unreasonably big. Around 777 JS files in our src directory.

I don't actually know how to debug this compilation speed problem. I'm not sure whether this is something with our Babel setup, whether I need to update a module, or whether my targets are set up incorrectly (I'm using the default >0.25%).

(P.S. I've tested the Parcel 1 100% CPU problem with a dummy app containing 1,000 files - and as I add more and more files to the app, the CPU usage goes up. At 1,000 files it's somewhere between 50-60%.)

šŸŽ› Configuration (.babelrc, package.json, cli command)

This is my .parcelrc:

{
  "extends": "@parcel/config-default",
  "transformers": {
    "*.svg": ["@parcel/transformer-svg-react", "@parcel/transformer-js"],
    "*.png": ["@parcel/transformer-raw"],
    "*.jpg": ["@parcel/transformer-raw"],
    "*.graphql": ["parcel-transformer-graphql-ast"],
  }
}

This is my babel.config.js:

module.exports = function(api) {
  api.cache(true);

  const presets = ['@babel/preset-react'];

  if (process.env['NODE_ENV'] === 'test') {
    presets.push([
      '@babel/preset-env',
      { modules: 'commonjs', targets: { node: 'current' } },
    ]);
  }

  const plugins = [
    [
      'auto-import',
      {
        declarations: [
          {
            default: 'React',
            path: 'react',
            members: ['useState', 'useEffect', 'useContext', 'useRef'],
          },
          { default: 'PropTypes', path: 'prop-types' },
          { default: 'classnames', path: 'classnames' },
          {
            default: 'withStyles',
            path: '@material-ui/core/styles/withStyles',
          },
        ],
      },
    ],
    [
      'babel-plugin-root-import',
      {
        paths: [
          { rootPathPrefix: '~', rootPathSuffix: 'src' },
          { rootPathPrefix: '#', rootPathSuffix: 'test' },
        ],
      },
    ],
    [
      'transform-inline-environment-variables',
      {
        include: [
          'CONTACT_SALES_FORM_ID',
          'CONTACT_SUCCESS_FORM_ID',
          'SENTRY_FRONTEND_DSN',
        ],
      },
    ],
    '@babel/plugin-syntax-import-meta',
    '@babel/plugin-proposal-class-properties',
    '@babel/plugin-proposal-function-sent',
    '@babel/plugin-proposal-export-namespace-from',
    '@babel/plugin-proposal-numeric-separator',
    '@babel/plugin-proposal-optional-chaining',
    '@babel/plugin-proposal-throw-expressions',
  ];

  return {
    presets,
    plugins,
  };
};

If anybody has any suggestions on where I should be looking, I'd love to get to the bottom of this, in case anybody else sees the same thing.

šŸ¤” Expected Behavior

It should be wicked fast! Parcel 1 was very fast, although it did seem to hog a single CPU core at 100% for our application.

šŸ˜Æ Current Behavior

Hot module reloading builds in Parcel 1 took ~200ms, and the same type of builds in Parcel 2 take anywhere between 2-4 seconds.

A hot reload looks like:

yarn run v1.22.4
$ NODE_ENV=development parcel index.html --no-autoinstall --public-url /dist
ā„¹ļø Server running at http://localhost:1234
āœØ Built in 4.32s

Parcel 1: ezgif-4-298363069598

Parcel 2: ezgif-4-19704afae25c

šŸŒ Your Environment

Software Version(s)
Parcel 2.0.0-beta.1
Node v13.14.0
npm/Yarn yarn 1.22.4
Operating System macOS
mischnic commented 3 years ago

babel.config.js

That is detrimental at least for production builds. I think every JS file is being reprocessed. Could you try to use a babel.config.json with an env key instead? https://babeljs.io/docs/en/6.26.3/babelrc#env-option

mischnic commented 3 years ago

Also: can you try to adding --no-hmr and seeing if the "Built in ..." time is faster? Trying to isolate the cause....

elliottkember commented 3 years ago

I moved to a babel.config.json file without any change in hot reloading times, and adding --no-hmr gives me Built in 3.69s, ranging between 3 and 8 seconds. I don't know quite what reprocessing all the files entails, so that might be happening, but at least it only shows Building index.js.... The little loading spinner in the command line prompt stops turning during that step.

elliottkember commented 3 years ago

@mischnic I figured out the problem with Parcel 1 - it was that fsevents is an optional dependency for chokidar which is used for the file watcher - after I installed fsevents@1, parcel 1 is lightning fast. I haven't found a way for yarn to install fsevents - it ignores it as an optionalDependency and I don't know why. Probably because it's very old.

mischnic commented 3 years ago

You probably can't share your code?

Are you using the most recent nightly?

You can run Parcel with --profile which emits a file that can be loaded into Chrome devtools and shows a flamegraph of all operations.

devongovett commented 2 years ago

@mvpix is that showing a build after editing a single file, or is that a fresh build of your whole app? Any more info you can provide that could help?

justinfarrelldev commented 2 years ago

This sounds almost exactly like an issue I'm also having. I'm also using React on Mac with Parcel 2, it can take upwards of 100 seconds to build my app (quite large app, but Parcel 1 did it blazingly fast).

mischnic commented 2 years ago

@justinfarrelldev Can you share more details? Is this with/without cache, development/production build? A profile via parcel build --profile would also be interesting

justinfarrelldev commented 2 years ago

@mischnic In trying to get you the profiling info, I actually realized my version of Parcel was different and quite old, going up to 1.12.3 fixed my problem. Thank you though!

vcarel commented 2 years ago

I have the same problem on my end. HMR is very slow, about 5s to 10s (parcel@2.0.1)

mischnic commented 2 years ago

There's still nothing we can do here without a reproduction.

vcarel commented 2 years ago

It says "building", "bundling", "packaging", "optimizing". All those step take equal time, except bundling, which is faster.

If I reduce the size of my project to... 1 file, it takes 300 to 500ms to build. But the project is quite big (387 ts and js files, 98 .module.scss files). Maybe it's just that?

For the record, the built files are quite big too:

-rw-rw-r-- 1 vianney vianney  18M nov.  22 18:06 index.8c718e25.js
-rw-rw-r-- 1 vianney vianney  24M nov.  22 18:06 index.8c718e25.js.map
-rw-rw-r-- 1 vianney vianney 602K nov.  22 18:06 index.f8b2c0e1.css
-rw-rw-r-- 1 vianney vianney 258K nov.  22 18:06 index.f8b2c0e1.css.map
mischnic commented 2 years ago

Indeed, a build of

import * as fluent from "@fluentui/react";
import * as spectum from "@adobe/react-spectrum";
import * as antd from "antd";
import * as moment from "moment";
import * as React from "react";
import * as ReactDOM from "react-dom";

console.log(fluent, spectum, antd, moment, React, ReactDOM);
console.log(2) // change to different number

is a 9.4mb bundle and takes 2-3s to build after a trivial change.

Bundling takes 1.1s (we are already working on speeding that part up) Something like https://github.com/parcel-bundler/parcel/issues/4143 would help, because for many basic changes, only the single changed asset is needed in the browser, not the whole new bundle.

mkaraula commented 2 years ago

@mischnic I am having the same Issue adding changing one line takes 8s to rebuild on a quite big project.

How can I send you the profile?

dsgkirkby commented 1 year ago

I also ran into this when trying to convert an app to parcel - in our case, it typically takes about 10s for parcel to rebuild after changing just a single file. In the case of the trace below it actually took 15s (maybe unlucky, maybe overhead?)

Here's the trace: profile-20220731-134852.trace.zip

mischnic commented 1 year ago

@dsgkirkby This applies to you as well: https://github.com/parcel-bundler/parcel/issues/4143#issuecomment-997528950

"bundling" takes the most time in your case.

If you want to try the new bundler right now, do this: https://github.com/parcel-bundler/parcel/issues/5772#issuecomment-1133377231 (you don't have to necessarily use the nightly version)


How can I send you the profile?

Using parcel index.html --profile.

dsgkirkby commented 1 year ago

@mischnic Thanks for the reply! I tried this (v2.6.2, the nightlies cause errors because some of their deps are for a nightly that's 2.0.0-something) and it improved things a decent amount - incremental builds are now ~5-6s, though this is still a bit slower than the 1-3s I'm used to with webpack. It also fixed https://github.com/parcel-bundler/parcel/issues/8350 which I ran into with the default bundler!

However, the experimental bundler isn't including a bunch of my CSS (seems like everything that's in index-dev.[hash].css in the older bundler) on the page so lots of my styles are broken - is there somewhere I should file that bug?

devongovett commented 1 year ago

Should be a lot faster in v2.8. https://parceljs.org/blog/v2-8-0/