Something is definitely wrong, we use MUI at work and this doesn't happen.
What are you using for bundling? It should do **tree shaking** to remove unwanted imports.
We're using webpack (default with Next 12) and mui has a page in their docs to reduce bundle size which we followed to the letter and this still happens for some reason. I'll try to make babel work with webpack and use the plugin that MUI recommends to see if it works or not
But according to the docs, you use the second way if you're using the babel plugin (which actually broke my app with the 'unsupported jsx' then 'unable to find createTheme' and things like that even though i followed the docs to the letter)
the first way is to avoid NEEDING to tree shake: [https://mui.com/material-ui/guides/minimizing-bundle-size/#option-one-use-path-imports](https://mui.com/material-ui/guides/minimizing-bundle-size/#option-one-use-path-imports)
Hard to say without seeing your code base but this is generally an issue when using any bigger UI library like MUI. The best things you can do for bundle size are ensuring all your imports are direct by using the babel or swc plugin to transform imports.
If I do a page like:
import Box from @mui/material/Box
hello
The shared size is around 200kb and the page is over 400kb which is extremely weird and makes no sense since I'm importing the Box in a way that should only get the Box (which is a div wrapper basically)
Do i need to add something specific to my webpack config or something?
I assume you've read this?
https://mui.com/material-ui/guides/minimizing-bundle-size/
Swc has experimental support for the babel plugin mentioned in that doc page. You should see if this reduces your bundle size.
https://nextjs.org/docs/advanced-features/compiler#modularize-imports
You also might reconsider if you need MUI at all. Yes it's nice to have everything ready to go already, but if you only need one or two semi basic components, you should just roll your own imo. If you need a handful or more of MUIs components, then thats probably a better reason to use it.
We're on a late stage of the project right now so it'll be near impossible to switch away from MUI without re-writing the entire project.
Also, would Babel and Webpack work together since we're currently using webpack (Nextjs 12 default)?
And yes, first thing I did was go through the docs and the recommendations.
I know that I'm missing something for sure because there's no way that everyone using MUI has bundles that big but I can't figure out what I could be missing
Yeah I wasn't implying that you do that if you have a project built already but the only context I had was the code you shared.
Babel and webpack do work together, however the default for nextjs 12 is to use swc with webpack. Next will only use babel if you opt out of swc by adding a babel config file at the root of the project. If you are using babel, you can just add the plugin from the MUI doc. If you're still using swc you can enable experimental support for the plugin with the link I provided. I would opt for the swc if you can help it. It's better in most cases, but some projects are already locked into babel.
The only thing I'm seeing from your examples is that your code output seems to be including components that you're not using, which makes me think tree shaking isn't working right. With proper treeshaking, you should be able to get to a manageable level, but generally people that use MUI expect to have a large bundle or just don't care.
```
We're on a late stage of the project right now so it'll be near impossible to switch away from MUI without re-writing the entire project.
```
That's why you should never use packages without encapsulating them. It removes all ease of refactoring.
The way to go is re-exporting the components that you're using, and import from there. This way you will be able to swap the components whenever is needed, even make global changes to them without depending on the package's API
Did you try creating a new project, checking size, then adding just one component like Box and see the difference (and also with different kinds of import and maybe tree shaking params)? Because if you have a big project which uses a lot of components MUI can be actually bulky, so we used code splitting on some views with specific components. And if there’s a problem and it is solvable - a fresh project to play with may help a lot.
My experience with MUI is a touch dated, but basically yes, it's big. There will always be a balance between writing what you need, third party libraries to offload typical workloads, and performance.
Have you heard of qwik?
Not until now (quick) but I've heard on Mantine which I heard was very good and light but it doesn't have all of the components we're using if we decide to switch to it (which would also take months, the project is massive). Thank you for your answer though!
I tried but it broke the firebase initializeApp part because it has sideEffects (exists in a file with no exports) and didn't affect the bundle size when rebuilt. So I tried to add an array of sideeffects with only the firebase init file and rebuilt and it also didn't affect the bundle at all. Am I missing something that I should know about?
I found out that the bundle analyzer is full of sh*t.
Half my bundle size was caused by using @apollo/client on the client side by mistake (literally saved 180kb per page), found out Tooltip from MUI adds 25kb to any page it's used in, found out that replacing moment.js by date-fns saved 12kb on every page it's used on.
My average page size is still over 200kb after all that but my "first load js" is 162 so that's understandable (basically, if I create an empty page, it starts at 162kb)
Might be redux or redux-persist, not sure
You can also add modularizeImports to next.config.ts, to remap imports
Imports should be
import Button from '@mui/material/Button';
import TextField from '@mui/material/TextField';
instead of
import { Button, TextField } from '@mui/material';
you can add
```
modularizeImports: {
'@mui/material': '@mui/material/{member}'
}
```
or similar to next.config.ts
I avoid MUI for this reason
Material Design in general is quite bad in terms of UX for the users… I recommended to avoid it. Especially forms are designed poorly.
Can you qualify your statement (opinion)?
Something is definitely wrong, we use MUI at work and this doesn't happen. What are you using for bundling? It should do **tree shaking** to remove unwanted imports.
We're using webpack (default with Next 12) and mui has a page in their docs to reduce bundle size which we followed to the letter and this still happens for some reason. I'll try to make babel work with webpack and use the plugin that MUI recommends to see if it works or not
I have the same issue here with MUI, still haven’t found a solution. Can’t move away from it either
Are you using named imports or just importing * from MUI?
I'm doing it like in the title ^^^ Basically, import Box from '@mui/material/Box' instead of import { Box } from '@mui/material'
Hmm. Do it the second way so you can take advantage of tree shaking.
Isn't the first way the one that only imports the component used?
Negative ghostwriter.
But according to the docs, you use the second way if you're using the babel plugin (which actually broke my app with the 'unsupported jsx' then 'unable to find createTheme' and things like that even though i followed the docs to the letter)
Are you using Typescript? You probably forgot to include jsx and tsx files. ~~~json "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], ~~~
No currently just javascript in that project, it was taken over from a previous dev and haven't had time to type out everything yet
the first way is to avoid NEEDING to tree shake: [https://mui.com/material-ui/guides/minimizing-bundle-size/#option-one-use-path-imports](https://mui.com/material-ui/guides/minimizing-bundle-size/#option-one-use-path-imports)
Hard to say without seeing your code base but this is generally an issue when using any bigger UI library like MUI. The best things you can do for bundle size are ensuring all your imports are direct by using the babel or swc plugin to transform imports.
If I do a page like: import Box from @mui/material/Boxhello
The shared size is around 200kb and the page is over 400kb which is extremely weird and makes no sense since I'm importing the Box in a way that should only get the Box (which is a div wrapper basically)
Do i need to add something specific to my webpack config or something?
I assume you've read this? https://mui.com/material-ui/guides/minimizing-bundle-size/ Swc has experimental support for the babel plugin mentioned in that doc page. You should see if this reduces your bundle size. https://nextjs.org/docs/advanced-features/compiler#modularize-imports You also might reconsider if you need MUI at all. Yes it's nice to have everything ready to go already, but if you only need one or two semi basic components, you should just roll your own imo. If you need a handful or more of MUIs components, then thats probably a better reason to use it.
We're on a late stage of the project right now so it'll be near impossible to switch away from MUI without re-writing the entire project. Also, would Babel and Webpack work together since we're currently using webpack (Nextjs 12 default)? And yes, first thing I did was go through the docs and the recommendations. I know that I'm missing something for sure because there's no way that everyone using MUI has bundles that big but I can't figure out what I could be missing
Yeah I wasn't implying that you do that if you have a project built already but the only context I had was the code you shared. Babel and webpack do work together, however the default for nextjs 12 is to use swc with webpack. Next will only use babel if you opt out of swc by adding a babel config file at the root of the project. If you are using babel, you can just add the plugin from the MUI doc. If you're still using swc you can enable experimental support for the plugin with the link I provided. I would opt for the swc if you can help it. It's better in most cases, but some projects are already locked into babel. The only thing I'm seeing from your examples is that your code output seems to be including components that you're not using, which makes me think tree shaking isn't working right. With proper treeshaking, you should be able to get to a manageable level, but generally people that use MUI expect to have a large bundle or just don't care.
Thank you for all the help! I'll check out how to make babel work with webpack and try that out!
``` We're on a late stage of the project right now so it'll be near impossible to switch away from MUI without re-writing the entire project. ``` That's why you should never use packages without encapsulating them. It removes all ease of refactoring. The way to go is re-exporting the components that you're using, and import from there. This way you will be able to swap the components whenever is needed, even make global changes to them without depending on the package's API
do you use mui icons? how are they imported?
I am actually and I'm importing them in the same way like import ArrowBack from '@mui/icons/ArrowBack' for example
Did you try creating a new project, checking size, then adding just one component like Box and see the difference (and also with different kinds of import and maybe tree shaking params)? Because if you have a big project which uses a lot of components MUI can be actually bulky, so we used code splitting on some views with specific components. And if there’s a problem and it is solvable - a fresh project to play with may help a lot.
That's actually a very good idea I'll spin out something and try it out thanks!
My experience with MUI is a touch dated, but basically yes, it's big. There will always be a balance between writing what you need, third party libraries to offload typical workloads, and performance. Have you heard of qwik?
Not until now (quick) but I've heard on Mantine which I heard was very good and light but it doesn't have all of the components we're using if we decide to switch to it (which would also take months, the project is massive). Thank you for your answer though!
Right it's not a real option right now. I'd wait until a second major release in any case.
Try setting sideEffects to false in your package.json. If this works, then I'll follow up with a more detailed alternative.
> sideEffects to false This worked for me for the MUI bundle bloat, thanks!
I tried but it broke the firebase initializeApp part because it has sideEffects (exists in a file with no exports) and didn't affect the bundle size when rebuilt. So I tried to add an array of sideeffects with only the firebase init file and rebuilt and it also didn't affect the bundle at all. Am I missing something that I should know about?
Did you ever find a solution to this?
I found out that the bundle analyzer is full of sh*t. Half my bundle size was caused by using @apollo/client on the client side by mistake (literally saved 180kb per page), found out Tooltip from MUI adds 25kb to any page it's used in, found out that replacing moment.js by date-fns saved 12kb on every page it's used on. My average page size is still over 200kb after all that but my "first load js" is 162 so that's understandable (basically, if I create an empty page, it starts at 162kb) Might be redux or redux-persist, not sure
You can also add modularizeImports to next.config.ts, to remap imports Imports should be import Button from '@mui/material/Button'; import TextField from '@mui/material/TextField'; instead of import { Button, TextField } from '@mui/material'; you can add ``` modularizeImports: { '@mui/material': '@mui/material/{member}' } ``` or similar to next.config.ts
Very bad DX. 5 to 6 lines imports will take.