Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modules import and destructuring performances

I recently read on Material-UI's docs:

Notice that in the above example, we used:

import RaisedButton from 'material-ui/RaisedButton'

instead of

import {RaisedButton} from 'material-ui'

This will make your build process faster and your build output smaller.

I used to thought that it was exactly the same, but actually, this means that the second lines is juste like:

import materialUI from 'material-ui'
const {RaisedButton} = materialUI

And it will produce the exact same bundle, right?

I did some tests, comparing bundles size use different combinaisons of importing with 2 files:

index.js:

import RaisedButton from 'material-ui/RaisedButton'
// or import {RaisedButton} from 'material-ui'
import file from './otherFile.js'

console.log(RaisedButton)
console.log(file)

otherFile.js

import RaisedButton from 'material-ui/RaisedButton'
// or import {RaisedButton} from 'material-ui'

export default RaisedButton

The results are quite as expected using only import RaisedButton from 'material-ui/RaisedButton' the bundle will be something like 24k LoC (material-ui loads React dependencies). Using import {RaisedButton} from 'material-ui', in one or both file(s), the bundle will be something like 57k LoC.

My question is mainly about performances and best practices, with a small usage of Material-UI I should always import from 'material-ui/ComponentName, but if I use a lot of Material-UI components on a bigger project, it won't impact the bundle size if I use import {Comp1, Comp2, Comp3} from 'material-ui' as the whole package will be imported only one time in the bundle?

like image 577
Cohars Avatar asked Jul 03 '16 15:07

Cohars


2 Answers

Yes that is correct. By doing this:

import {RaisedButton} from 'material-ui'

The root library file of 'material-ui' will be included. Inside of that file, it will likely have a lot of import RaisedButton from './RaisedButton' statements to include all the components of the library at once (see https://github.com/callemall/material-ui/blob/master/src/index.js).

Doing:

import RaisedButton from 'material-ui/RaisedButton'

all the time will gurantee better performance in terms of bundle size as you will only be getting only the dependencies you need. If you only use a few components, this will also improve the build speed as it will not need to parse the files for the other components in the library.

If you are using all or almost all the components in the library, the build performance should be about the same because if both the root script of 'material-ui' and your file both require the same component twice, your bundler will be smart enough to cache the result and will not re-parse the files. Your bundler will make over-importing the same thing a cheap operation in this case.

I'd recommend using the import RaisedButton from 'material-ui/RaisedButton' syntax as this is more adaptive to your needs over time as you may not always need all the components and it will be unlikely that you are using all of them at once. Additionally some bundlers such as webpack support bundle splitting which wouldn't be easy with the import {RaisedButton} from 'material-ui' method.

like image 193
Dennis Shtatnov Avatar answered Nov 14 '22 20:11

Dennis Shtatnov


If you use Webpack, the destructuring syntax should help remove unused Javascript from the output file, because Webpack supports Tree-Shaking, provided the following conditions are met (quoted from webpack's website):

  • Use ES2015 module syntax (i.e. import and export).
  • Ensure no compilers transform your ES2015 module syntax into CommonJS modules (this is the default behavior of popular Babel preset @babel/preset-env - see documentation for more details).
  • Add a "sideEffects" property to your project's package.json file.
  • Use production mode configuration option to enable various optimizations including minification and tree shaking.
like image 27
conradkleinespel Avatar answered Nov 14 '22 18:11

conradkleinespel