Repository: material-ui
Issue: [core] Flatten imports to speed up webpack build & node resolution
Labels: performance,priority: important,core,ready to take,enhancement

### What's the problem? 🤔

## Background

While playing around with Next.js, I installed a package that was using @mui. I immediately noticed huge delays running `next dev` and the large module count (10K+) listed in the terminal. Searching for an answer, I landed on a long list of requests for help:

- https://github.com/vercel/next.js/discussions/17977
- https://github.com/vercel/next.js/discussions/37614
- https://github.com/vercel/next.js/discussions/42343
- https://github.com/vercel/next.js/issues/29559
- https://github.com/vercel/next.js/issues/43285
- https://www.reddit.com/r/nextjs/comments/swciuj/next_dev_is_slow/

But none of those had an actual answer with an actual solution, just guesses and workarounds. One of the popular answers was: https://mui.com/material-ui/guides/minimizing-bundle-size/

After attempting to fix the library I pulled in by following the first option on that guide:
https://mui.com/material-ui/guides/minimizing-bundle-size/#option-one-use-path-imports

**I noticed that the module count was still in the thousands. Why?**

After reading everything on webpack, modules, tree shaking, etc, I made a demo application using [CRA](https://github.com/facebook/create-react-app) and a single import to @mui to showcase the problem.

## Problem

### Reproduction Steps
1. Run `npx create-react-app cra-test` to get the latest with Webpack 5
2. Ejected from CRA so that I could modify the webpack config for more metrics
3. Using webpack dev server, I modified [this](https://github.com/facebook/create-react-app/blob/19fa58d527ae74f2b6baa0867463eea1d290f9a5/packages/react-dev-utils/WebpackDevServerUtils.js#L162-L166) to see what modules traversed in development
4. Using webpack prod builds, I modified [this](https://github.com/facebook/create-react-app/blob/main/packages/react-scripts/scripts/build.js#L208-L213) to see modules traversed in production

I used the following configurations for `stats.toJson()` to balance the verbosity of the output. 
I tested with and without default imports for a single icon and component.
1. With default import `{assets: false, chunks: false, modulesSpace: 6, nestedModules: false, reasonsSpace: 10}`
2.  With path import: `{assets: false, chunks: false})`


### Demo App 1 - Default Import Icon
This is the scenario that we are told to avoid when using @mui, and for good reason. 
I created this as a baseline to see what webpack had to traverse.

```
import { AbcRounded } from '@mui/icons-material'

function App() {
  return (
      <div>
        <AbcRounded />
      </div>
  );
}
export default App;
```

### Demo App 1 - Webpack Metrics Output

As expected, using the default import for `AbcRounded` ended up pulling in all icons.

**Webpack Module Summary**
```
orphan modules 6.28 MiB [orphan] 10860 modules
runtime modules 28.5 KiB 14 modules
```

![image](https://user-images.githubusercontent.com/17555572/212615816-87654502-a76d-47dd-90d7-e7dbc721c5cd.png)


### Demo App 2 - Path Import Icon
Following the docs, you would expect an import like this to be lightweight. It isn't.

```
import AbcRounded from '@mui/icons-material/AbcRounded'

function App() {
  return (
      <div>
        <AbcRounded />
      </div>
  );
}
export default App;
```

### Demo App 2 - Webpack Metrics Output
**_This_** is the problem. Importing a [single icon](https://github.com/mui/material-ui/blob/master/packages/mui-icons-material/lib/AbcRounded.js) resulted in:

1. [Importing ./utils/createSvgIcon](https://github.com/mui/material-ui/blob/master/packages/mui-icons-material/lib/AbcRounded.js#L8)
2. [Importing @mui/material/utils](https://github.com/mui/material-ui/blob/master/packages/mui-icons-material/src/utils/createSvgIcon.js#L1)
3. [Importing a lot more...(doesn't fit in a single screenshot)](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/utils/index.js#L1-L19)

**Webpack Module Summary**
```
orphan modules 534 KiB [orphan] 274 modules
runtime modules 28.5 KiB 14 modules
```

![image](https://user-images.githubusercontent.com/17555572/212617521-5f78b4f9-ca86-4fa1-8d77-2290ab302cae.png)

### Demo App 3 - Path Import Component
This problem isn't unique to `@mui/icons-material` either. Here's performing a path import of a button.

```
import Button from '@mui/material/Button'

function App() {
  return (
      <div>
          <Button>Hello World</Button>
      </div>
  );
}
export default App;
```

### Demo App 3 - Webpack Metrics Output
Again, **_the problem_**. Importing a [single button](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Button/index.js) resulted in:

1. [Importing ./buttonClasses](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Button/index.js#L4)
2. [Importing @mui/utils](https://github.com/mui/material-ui/blob/master/packages/mui-material/src/Button/buttonClasses.ts#L1)
3. [Importing a lot more...(doesn't fit in a single screenshot)](https://github.com/mui/material-ui/blob/master/packages/mui-utils/src/index.ts#L1-L41)

**Webpack Module Summary**
```
orphan modules 573 KiB [orphan] 291 modules
runtime modules 28.5 KiB 14 modules
```

![image](https://user-images.githubusercontent.com/17555572/212618997-474a36de-caf1-4a01-8aa7-947eb5a61e08.png)

**We should not be importing hundreds of modules from a single icon or button.**

## But... Tree Shaking? Side Effects?
This was confusing for me too, and I had to go into the details to find the answer. 

1. [Webpack does not tree shake at the code level, it only tree shakes at the module level.](https://webpack.js.org/guides/tree-shaking/#clarifying-tree-shaking-and-sideeffects)
2. [Terser performs dead code elimination when minifying](https://webpack.js.org/guides/tree-shaking/#clarifying-tree-shaking-and-sideeffects), **but webpack still has to traverse all those imports!**
3. **This happens whether you are building for development or production.** 
4. [We "cue up" our code for deletion by using ESM, but it isn't done until the minification happens.](https://webpack.js.org/guides/tree-shaking/#minify-the-output)

Yes the bundle will still be minimized successfully when following ESM practices, but thousands of modules being traversed bloats memory and slows down development servers.

### What are the requirements? ❓

Importing from @mui should always result in a minimal dependency graph for that particular import.

### What are our options? 💡

#### Option 1 - Proposal
Apply transformations to the @mui build process to ensure a minimal dependency graph for all files.

#### Option 2 - Alternative
Remove all barrel files from @mui. This option isn't great as the developer experience that they provide is desired by both library maintainers and library users alike.

### Proposed solution 🟢

1. Apply import transformations _within_ @mui packages.

Showcased above, even when importing a component or icon directly, thousands of downstream modules get pulled in. This happens because within @mui itself, barrel files are being utilized for their developer experience. In that case, [why not follow the same recommendation that @mui gives,](https://mui.com/material-ui/guides/minimizing-bundle-size/) and add these transforms to the build process? 

2. Make ["modularize imports"](https://nextjs.org/docs/advanced-features/compiler#modularize-imports) work for all @mui packages

[In [docs] Modularize Imports for Nextjs](https://github.com/mui/material-ui/pull/35457), the comment https://github.com/mui/material-ui/pull/35457#issuecomment-1375499537 requested that the docs don't include `@mui/material` for import transformations via babel or swc, since there are outliers that cause the transformation to fail.

Instead of backing off here, the work should be put in to fix it. The same barrel files that @mui is using internally for better developer experience is what users of the library need as well. By fixing point 1, this will come for free.


### Resources and benchmarks 🔗

Below are the webpack metrics I collected for the applications in the background statement:
[mui-default-import-icon-truncated-metrics.txt](https://github.com/mui/material-ui/files/10423727/mui-default-import-icon-truncated-metrics.txt)
[mui-path-import-button-metrics.txt](https://github.com/mui/material-ui/files/10423730/mui-path-import-button-metrics.txt)
[mui-path-import-icon-metrics.txt](https://github.com/mui/material-ui/files/10423732/mui-path-import-icon-metrics.txt)