reactjswebpackmaterial-uicode-splitting

Why is material ui build so big


I'm trying to get Material-ui to tree-shake correctly. The bundle is extremely large compared to what I'm actually using. I'm not using most of the components listed by the analyzer plugin below and I'm importing everything like it says on the material-ui docs. For example here is what it looks like in one of my files.

import Button from '@material-ui/core/Button';
import CssBaseline from '@material-ui/core/CssBaseline';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
import Container from '@material-ui/core/Container';

In contrast, I use react-bootstrap in a very similar way and its size is much smaller.

enter image description here

Here is my webpack file

const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const fs = require('fs');
const WebpackOnBuildPlugin = require('on-build-webpack');
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');

const buildDir = './build/';

module.exports = {
  optimization: {
    usedExports: true,
  },
  entry: {
    build: './src/index.js',
  },
  plugins: [
    new BundleAnalyzerPlugin(),
    new LodashModuleReplacementPlugin(),
    new webpack.optimize.LimitChunkCountPlugin({
      maxChunks: 25,
    }),
    new MiniCssExtractPlugin(),
  ],
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
      {
        test: /\.s[ac]ss$/i,
        use: [
          // Creates `style` nodes from JS strings
          'style-loader',
          // Translates CSS into CommonJS
          'css-loader',
          // Compiles Sass to CSS
          'sass-loader',
        ],
      },
    ],
  },
  output: {
    chunkFilename: '[id].[contenthash].chunk.js',
    filename: 'bundle.js',
    path: path.resolve(__dirname, './build'),
  },
};

I thought that Material-UI would be pretty small (in the kb range) given that I'm using basic functionality.

Also, I'm also using code-splitting by route, but Webpack includes MUI in the main bundle because it's shared by a few chunks. That means that I have an extra mb in every route even if that page doesn't use material ui. Is there any way to code-split so only the individual MUI modules get loaded in their appropriate routes?


Solution

  • It looks like this happens with material-ui when you build in development. The production build tree-shakes correctly. Weirdly though, material-ui's own docs claim that if you do the direct file import, the dev build should tree-shake correctly too.