Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get Tree Shaking to work in Webpack 4 for React Library "material-ui"?

Although I followed the steps explained in the docs (see here) to enable Tree Shaking, it seems to have no effect. I'm using Webpack 4 with ts-loader for TypeScript. The library in question is material-ui. In their docs (see How to reduce the bundle size?) they recommend to "import directly from material-ui/ to avoid pulling in unused modules" and later they add "Both of the options should be temporary until you add tree shaking capabilities to your project.". So I assume that Tree Shaking should have some effect.

To be clear: They recommend to import like this:

import RaisedButton from "material-ui/RaisedButton";

And not like this:

import {RaisedButton} from "material-ui";

What I did:

  • Only used ES2015 module syntax (i.e. import and export).
  • Added a "sideEffects":false entry to my project's package.json file. And made sure the spelling is correct.
  • Ran Webpack in mode: "production", which Webpack 4 allows to use instead of UglifyJsPlugin ("As of webpack 4, this is also easily toggled via the "mode" config option, set to "production".")

Result: Nothing. No reduction in size. So maybe I'm doing something wrong?


For the benchmark lovers: This is what a single RaisedButton costs in terms of bundle size. Without minification (i.e. production mode):

Initial (in mode "development"): 
1,63 MiB (No Material UI)

MuiThemeProvider
1,94 MiB -> +0,31 (`import {MuiThemeProvider} from "material-ui/styles";`)
1,92 MiB -> +0,29 (`import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';`)

RaisedButton
3,07 MiB -> +1,13 (`import {RaisedButton} from "material-ui";`)
2,03 MiB -> +0,09 (`import RaisedButton from "material-ui/RaisedButton";`)

And with minification (no compression):

Initial (in mode "production"):
284 KiB (No Material UI)

MuiThemeProvider
371 KiB -> +087 (`import {MuiThemeProvider} from "material-ui/styles";`)
367 KiB -> +077 (`import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';`)

RaisedButton
705 KiB -> +338 (`import {RaisedButton} from "material-ui";`)
400 KiB -> +033 (`import RaisedButton from "material-ui/RaisedButton";`)

And with Tree Shaking enabled:

705 KiB (`import {RaisedButton} from "material-ui";`)
400 KiB (`import RaisedButton from "material-ui/RaisedButton";`)

I.e: No effect at all.

like image 811
ss1 Avatar asked Mar 21 '18 14:03

ss1


People also ask

How do I turn on a tree shaking webpack?

Add a "sideEffects" property to your project's package. json file. Use the production mode configuration option to enable various optimizations including minification and tree shaking.

Why is webpack not tree shaking?

In webpack, tree shaking works with both ECMAScript modules (ESM) and CommonJS, but it does not work with Asynchronous Module Definition (AMD) or Universal Module Definition (UMD).

Is material UI tree shaking?

When and how to use tree-shaking? Tree-shaking of Material-UI works out of the box in modern frameworks. Material-UI exposes its full API on the top-level material-ui import. If you're using ES6 modules and a bundler that supports tree-shaking ( webpack >= 2.


1 Answers

As @qx3 wrote, I've been able to get it by adding:

alias: { '@material-ui/core': '@material-ui/core/es' }

in my webpack config.

Note the '@' prefix and the '/core' suffix to adapt to the new naming of the library. This simple little thing, helped me to get rid of some bytes and enabled the team to write the '@material-ui/core' imports in a full esm compliant way.

like image 196
neatshell Avatar answered Oct 17 '22 09:10

neatshell