mui / material-ui

Material UI: Comprehensive React component library that implements Google's Material Design. Free forever.
https://mui.com/material-ui/
MIT License
94.07k stars 32.32k forks source link

Bundling MUI w/ Pigment CSS results in large JavaScript chunks #44113

Open o-alexandrov opened 1 month ago

o-alexandrov commented 1 month ago

Steps to reproduce

Link to live example

Steps:

  1. Clone the repo (it's exactly the same as the vite example from this repo)
    • I just added rollup-plugin-visualizer so you could visualize the resulting bundle
  2. Bundle npm run build
  3. Your browser will open automatically with the result from rollup-plugin-visualizer (see example below)
Screenshot 2024-10-15 at 1 41 25 PM

Current behavior

Total: 16.22KB gzipped

Expected behavior

Smaller JavaScript footprint

Context

We should evaluate the runtime implications of some PigmentCSS' API usage, such as: styled that results in extra JS output

Your environment

npx @mui/envinfo ``` System: OS: macOS 15.0.1 Binaries: Node: 22.9.0 - /opt/homebrew/bin/node npm: 10.8.3 - /opt/homebrew/bin/npm pnpm: 9.9.0 - /opt/homebrew/bin/pnpm Browsers: Chrome: 129.0.6668.91 Edge: 112.0.1722.39 Safari: 18.0.1 npmPackages: @emotion/react: 11.13.3 @emotion/styled: 11.13.0 @mui/core-downloads-tracker: 6.1.3 @mui/material: latest => 6.1.3 @mui/material-pigment-css: latest => 6.1.3 @mui/private-theming: 6.1.3 @mui/styled-engine: 6.1.3 @mui/system: 6.1.3 @mui/types: 7.2.18 @mui/utils: 6.1.3 @pigment-css/react: 0.0.24 @pigment-css/vite-plugin: latest => 0.0.24 @types/react: latest => 18.3.11 react: latest => 18.3.1 react-dom: latest => 18.3.1 typescript: latest => 5.6.3 ```

Search keywords: pigmentcss, pigment, bundling, final, emotion, zero runtime

mnajdova commented 1 month ago

In general, we are talking about two different things here, runtime performance vs bundle size. In general, we made a decision to make the theme available in the runtime too for some use-cases, like having access to it in the rendering logic etc. So, I would say that part of the bundle size increase is expected. In terms of how much code is being executed during runtime, from my understanding all of it is related to:

So zero-runtime namely means that there is no logic in generating stylesheet during runtime - this is the thing that is different than Emotion. @brijeshb42 can correct me or expand further.

Now, we may need to document these things so we don't set false expectations.

A question - have you compared a plain app using Emotion vs Pigment CSS? Is this related to adding Material UI too in the bundle? We can likely move this issue to the Pigment CSS repository

brijeshb42 commented 1 month ago

Current bundle size for zero-runtime-theme is controlled through @mui/material package. Pigment itself is only responsible for @pigment-css/react/build and that too would depend on the APIs that you are using and whether the bundler is tree-shaking unused exports or not. As for emotion being part of the bundle, I'll need to inspect the source and get back but ideally it should not be part of the bundle. As Marija already pointed out, zero-runtime here purely means that the css generation is not dependent on the runtime (whether browser or server). The actual bundle size will depend on how it is implemented. In this case, @mui/material is also injecting it's theme at runtime (through hooks in Pigment CSS) so that it is backward compatible.

o-alexandrov commented 1 month ago

Idk whether this issue can be improved by rethinking how you use the PigmentCSS’ API (styled vs css), or by optimizing runtime implications of the styled API.

On a side note, for my use case, the JS only size of an app actually grew in size after switching from Emotion to PigmentCSS. That's because @emotion-related deps still ended up in the final bundle (probably because @mui/lab or @mui/base are not processed with transformLibraries: ["@mui/material"])

For me, what worked to remove emotion completely was setting transformLibraries: ["@mui"]

o-alexandrov commented 1 month ago

what worked to remove emotion completely was setting transformLibraries: ["@mui"]

I mean to decrease use of emotion in a medium project with a lot of MUI components to 2.32KB gzipped as in the provided reproduction example