react-spectrum icon indicating copy to clipboard operation
react-spectrum copied to clipboard

Incompatible with chunking, large initial bundle sizes

Open jaens opened this issue 1 year ago • 3 comments

Provide a general summary of the issue here

When using a multi-chunk app (as suggested for client performance), all react-aria's components will always be entirely packaged into the first chunk that loads any one of them.
Since this is generally the root chunk, it bloats it up significantly if eg. the root only needs one component, but the rest of the app uses all of them.

This is tangentially related to #5639 (might be same root cause?) but different "result".

🤔 Expected Behavior?

When using react-aria modules in a multi-chunk app, the initial chunk should only include components it needs.

😯 Current Behavior

All components of an entire package are included into the first chunk.

💁 Possible Solution

It's quite simple underneath really - since all of the submodules in eg. react-aria-components are pre-compiled/bundled into a single dist/import.mjs file, there is no way this can work in any bundler, since AFAIK no bundler cuts up modules into smaller chunks. (confirmed with at least Vite, esbuild & rollup)

Tree-shaking of course "works", but has no significant effect once you start using a large portion of the components.

The solution is to not pre-bundle everything into import.mjs, but instead compile every component (ie. file) into a a corresponding separate <component>.mjs file, and then make import.mjs re-export them.

Bundlers AFAIK do see through this "simple" indirection and can then distribute the components into appropriate chunks.

🖥️ Steps to Reproduce

The bundle visualizer results in #5639 demonstrate this (the giant import.mjs blobs), although this is more relevant for react-aria-components, since it only uses a single npm module, while the others at least are divided into @react-aria/* subpackages.

Version

react-aria-components 1.0.1

jaens avatar Feb 04 '24 19:02 jaens

It should only be the components you used in your app not all of RAC, though yeah some bundlers won't code split it if you only use Button on one page and ComboBox on another. Not sure how common that is. I would like to split the dist folder into multiple files (one per component) instead of one large file, but need to do some work on Parcel to support that while still producing commonjs, esm, and node esm versions of each one. The start of that work is over in https://github.com/parcel-bundler/parcel/pull/9489

devongovett avatar Feb 06 '24 22:02 devongovett

@devongovett Yes, as I mentioned, this applies indeed to only components being used, the problem is chunking them, if you do use a lot but in different parts.

Not sure how common that is.

I would guess anyone who follows React/bundling performance best practices uses multi-chunk apps. It mostly affects large apps that can be chunked easily.

some bundlers won't code split

AFAIK, no bundlers will code split in this situation (ie. split a single module into something smaller). Do you know of any? I'd sure like to use one... As I mentioned, at least esbuild and rollup do not.

jaens avatar Feb 07 '24 00:02 jaens

Maybe the description was a bit too abstract, here's a more concrete case:

The app consists of a:

  • navigation shell (might use Menu & similar)
  • textual pages (generally use no components)
  • table & visualization pages (use lots of different components)
  • form pages (use form components)

Sum total: All components used.

But: The initial load is into textual content with the navigation shell. It would be nice not to need to download a large chunk of JS just for that. Not sure such a situation is common, but I would guess it's not too uncommon...

jaens avatar Feb 07 '24 13:02 jaens

https://github.com/parcel-bundler/parcel/pull/9489 should allow us to improve this a lot. Will split each component into a separate file in the dist dir allowing sideEffects: false in package.json to be effective, and enabling code splitting. An example app I tested got 4x smaller. Once that's merged I'll make a PR with the changes needed on our end.

devongovett avatar Mar 05 '24 03:03 devongovett

Nice, with RAC v1.2.0, our initial bundle size dropped >50%!

jaens avatar May 03 '24 16:05 jaens