nextui-org / nextui

🚀 Beautiful, fast and modern React UI library.
https://nextui.org
MIT License
20.45k stars 1.24k forks source link

[Feature Request] Async framer-motion loading #3340

Open luzat opened 1 week ago

luzat commented 1 week ago

Is your feature request related to a problem? Please describe.

Just adding a NextUI button increases bundle size a lot. framer-motion contributes 212 KB (uncompressed) in a production build here. It would be nice if a that could be reduced or loaded asynchronously.

A second problem is, that Framer Motion is also be loaded if animations are disabled with disableAnimation={true}.

Describe the solution you'd like

According to the framer Motion guide it's possible to load features asynchronously using a dynamic import. For many use cases quick initial loading would be preferable over having animations loaded right away.

2929 already did most of the work required from what I can tell. In a test, I did replace the domAnimation in the ripple effect by a dynamic port and Vite did split the 212 KB framer-motion chunk into 59 KB to be loaded initially and a large 150 KB (or 45 KB with Brotli) chunk that can be loaded asynchronously. I feel that this is a huge amount. Also, if the dynamic import is never invoked when disableAnimation={true}, this code would never have to be downloaded.

I do not know if any other components would not work with that pattern or if there are cases when you might want to load the features synchronously. There could be at least two ways to go about this:

Even if code splitting won't work in all cases/components, this might be a helpful optimization for some projects.

Describe alternatives you've considered

Screenshots or Videos

No response

linear[bot] commented 1 week ago

ENG-1060 [Feature Request] Async framer-motion loading

wingkwong commented 1 week ago

Thanks for the info. We're also investigating this issue as well.

wingkwong commented 6 days ago

@luzat can you also share what tool you used and how you recorded the size?

luzat commented 6 days ago

@wingkwong I set up a basic Remix v2 project with Vite and mostly default settings. I manually added NextUI according to the documentation with single components (only Button and its animation dependencies). I added a single button to the _index route.

I checked the bundles that were generated with NODE_ENV=production npx vite-bundle-visualizer. The _index route included 212 KB from framer-motion. After patching the ripple effect to dynamically import domAnimation the _index route shrank by 150 KB and a separate chunk of that size, which contained a large part of framer-motion, was created instead. The _index route still dynamically loaded that chunk, but did not need that code for the initial render.

I did not test with disabled animations, but in that case the import should have been skipped, given that the animation is included conditionally, and 45 to 150 KB saved.

xiaoluoer commented 3 days ago

I seem to be getting this error: Warning: React does not recognize the disableAnimation prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase disableanimation instead. If you accidentally passed it from a parent component, remove it from the DOM element. The reason is caused by the Avatar component 截屏2024-07-01 16 52 45

wingkwong commented 3 days ago

@xiaoluoer this is another issue which I've fixed already. See here. The fix will be available in the next bug fix release.