Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incompatible with chunking, large initial bundle sizes #5798

Closed
jaens opened this issue Feb 4, 2024 · 5 comments · Fixed by #6064
Closed

Incompatible with chunking, large initial bundle sizes #5798

jaens opened this issue Feb 4, 2024 · 5 comments · Fixed by #6064

Comments

@jaens
Copy link

jaens commented Feb 4, 2024

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

@devongovett
Copy link
Member

devongovett commented Feb 6, 2024

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 parcel-bundler/parcel#9489

@jaens
Copy link
Author

jaens commented Feb 7, 2024

@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
Copy link
Author

jaens commented Feb 7, 2024

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...

@devongovett
Copy link
Member

parcel-bundler/parcel#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.

@jaens
Copy link
Author

jaens commented May 3, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants