Tree-shaking (material-ui) : [ERR_REQUIRE_ESM]

Hi,

Using the bundle analyser I see that Material UI takes up nearly 400kb of space, and it appears to includes the entirety of the project.

My imports are all of this style:

import { Box, Card, CardContent, Typography, Button, Link, FormControlLabel, Checkbox, Container, Dialog } from '@material-ui/core';

The Material UI documentation suggests that nothing else is needed for modern frameworks that support 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.x, parcel with a flag) you can safely use named imports and still get an optimised bundle size automatically

That’s not what I’m seeing with Meteor 1.10, which I’d definitely consider to be modern. So I then decided to use the babel-plugin-transform-imports plugin to convert my imports to separate lines as suggested here. This is my configuration:

  "plugins": [
    ["transform-imports", {
      "@material-ui/core": {
        "transform": "@material-ui/core/esm/${member}",
        "preventFullImport": true
      }
    }]
  ],

This configuration result in compilation errors:

Error [ERR_REQUIRE_ESM] [ERR_REQUIRE_ESM]: Must use import to load ES Module: /<snip>/node_modules/@babel/runtime/helpers/esm/extends.js

W20200527-09:08:07.152(2)? (STDERR) require() of ES modules is not supported.
require() of /<snip>/node_modules/@babel/runtime/helpers/esm/extends.js from /<snip>/node_modules/@material-ui/core/esm/CssBaseline/CssBaseline.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
W20200527-09:08:07.152(2)? (STDERR) Instead rename extends.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /Users/Tim/Development/MyApps/coco-et-lili/node_modules/@babel/runtime/helpers/esm/package.json.

I did however manage to make this work with a slight tweak to the babel config by removing the /esm from the path (as suggested on the Material UI site for 'if your bundler does not support ES modules’:

 "transform": "@material-ui/core/${member}",

This compiles, and delving into the compiled source I see that it’s done its job. However, it made absolutely no difference at all to the bundle size - the whole of Material UI is still imported into the initial bundle.

Continuing my research I fell across this site: https://www.ninjapixel.io/meteor-bundle-size.html

Here the author uses a different plugin (babel-plugin-direct-import) successfully, however when I try I get the same ERR_REQUIRE_ESM errors that I did above.

Has anyone here had this problem?
Did you solve it?
Why isn’t Meteor successfully tree shaking Material UI by default?

Regards,

Tim

1 Like

This worked for me:

"plugins": [
  // other plugins,
  [
    "babel-plugin-direct-import",
    {
      "modules": [
        "@material-ui/core",
        "@material-ui/icons",
        "@material-ui/styles"
      ]
    }
  ]
]

That’s just gives me the ERR_REQUIRE_ESM error :frowning:

require() of /snip/node_modules/@babel/runtime/helpers/esm/extends.js from /snip/node_modules/@material-ui/core/esm/CssBaseline/CssBaseline.js is an ES module file as it is a .js file whose nearest parent package.json contains “type”: “module” which defines all .js files in that package scope as ES modules.