Why do named imports cause slower builds and larger output? - javascript

I was looking at the material-ui documentation and saw the below comment about how to properly do an import in ES6.
What is the technical reason that doing a named import is slower and causes larger output?
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. For a complete mapping of Material-UI components to import, see /index.js inside the Material-UI npm package root directory.

That's not exactly enough context to see what's happening.
There are two separate things going on.
Default exports are typically going to be bigger than property exports.
export default ObjectWithAllKindsOfStuff {}
export function someFunction () { }
The second one is going to be smaller, practically 100% of the time, if they're in the same file.
Importing a single function from #angular/core is going to require opening a whole lot more files (taking longer) than importing everything from #angular/a/b/c/d/e/f.js.
If you are in the root folder's index.js, and you export * from './a', and in there, you export * from './b', et cetera... then for WebPack or Rollup or whatever, it has to load all of the files below, to figure out what each one exports, so it can tell where the function actually lives.
Their example is actually unfair, in that using the import { x } from 'package/SubPackage/SubSubPackage'; is going to be even smaller than import All from 'package/SubPackage/SubSubPackage';, but if you import { x } from 'pacakge'; and it has to go all the way through every folder, spidering through all of the exports, to figure out which file the function comes from, that's the comparison they're really making - it has nothing to do with the export {property} from versus export Namespace from if they're both talking about the same file, in the same subfolder.

Related

Best practice for importing component from components library in React.js

When I create components in React, they're all in a folder called component and each component has a dedicated folder with the same name as the component itself, e.g. ../components/Input.
But a big concern is about naming files. In order to avoid having to long paths, I name the component inside the folder Index.tsx so that when I import, I'll only have ../components/Input otherwise, it would be a very ugly import path like ../components/Input/Input.
So, by naming Index.tsx, in my IDE, I end up having too much index files open and then I get lost.
So what I did was to rename all those components file with the same name as the folder Input.tsx and exporting them using named export like export const Input:React.FC<InputProps>=(props)=>{...}, then at the root of my component folder, I created one index.tsx file where I export all those components so that while importing them in my pages, I can just write import {Input} from "../components".
I like this approach, but my next concern is about tree shaking. Because I don't want to import every time the entire components library.
So with the above approach, does React handle automatically tree shaking for us?
There's a tweet about the possible issues related to re-exporting everything with index files.
If your project has a components/index.js file which re-exports all your components (and does nothing else), that’s one example.
This is bad for performance – for two reasons.
It makes code splitting ineffective.
When you do
import { Button } from './components'
you’re importing not only Button but the whole ‘./components’ file. Which means you’re bundling the whole file – with all the components it exports.
It makes bundle initialization more expensive.
Every time a browser downloads the bundle, it has to execute it – and all its modules as well. If there’re a lot of modules, or some of them do something expensive, this can take a while.
Someone else suggests configuring webpack's sideEffects option so that the tree-shaking can still optimize the bundle as much as possible.
What I'm suggesting is to create small component modules inside the components directory.
- components/
- Input/ # component module
- index.ts # exports public API
- Input.tsx # actual component implementation
- Input.test.tsx
- Input.scss
- Input.stories.tsx
- etc.
Where the index.ts only re-export the public API for this component.
// index.ts
export { Input } from './Input';
export type { InputProps } from './Input';
// etc.
So that we have non-repeating paths when importing, but the filename we're actually working with is named according to the component.

Better way to import files for webpack bundle size

hooks/index.js
export { default as useDialog } from './useDialog'
export { default as useCurrencies } from './useCurrencies'
export { default as useUser } from './useUser'
Let's imagine that I have 3 files in hooks folder (useDialog, useCurrencies, useUser) . I want to make the correct imports from this folder. Now I do imports like this :
import {useDialog} from 'hooks'
Is it correct way to import this file , or it is better to import it like import useDialog from 'hooks/useDialog' ? What is better for my bundle size ?
You can try yourself and compare the bundle sizes on production from before and after. I'm gonna explain how to do it if anyone needs it.
First do these steps with the code importing from the index: import {useDialog} from 'hooks'
yarn build
serve -s build
Open the local address (http://localhost:5000/) on incognito mode. Then open Inspect -> Coverage.
At the bottom you can see the size. e.g: 1.2MB of 2.1MB (55%) used so far 964kB unused
Then change your code and import directly from the file: import useDialog from 'hooks/useDialog', and repeat the build and check the size.
Maybe if the files are too small you are not going to notice a difference, but you will if there are any big files or files that imports a big external library.
I tried this comparison on my project and there was one file importing and using moment. I was not even using this component, but the bundle size was increased because I was importing another component from the same index.
Before I was always importing from a folder like 'hooks', but from now on I will always import directly from the file 'hooks/useDialog'.
I'm just sharing my experience! Please, compare the bundles on your own projects!

ES6 Modules - 3 ways of importing files

Hello guys i have a little question about importing files into a single .js file.
Which way is better (best practice), what's the scenario that is used for:
import './file;'
import { something } from './file'
import * as evertything from './file'
Because i see that 2 and 3 are the same thing but different syntax(maybe Syntactic Sugar).
All three do different things.
import './file;'
That loads the file, and does not import anything. This is useful if you want to initialize that module (or add some external dependency, e.g. a css file if you use Webpack).
import { something } from './file'
That just imports something from the file, therefore a bundler could optimize all other dependencies away. I'd always try to go with that instead of
import * as evertything from './file'
That imports everything from that module under a namespace, and therefore makes treeshaking more difficult (the bundler cannot optimize it well). I'd only use that if you need everything from that dependency, or if that dependency is loaded externally nevertheless (e.g. import * as React from "react").
I guess the following MDN documentation will make you clear about those things:
import - JavaScript|MDN
As far as I know, 1st method is used when you have only one default export. 2nd is used when you have multiple default exports but you don't want all of them to load and want only few of them. 3rd is the case when you want everything under a single object (which can be used similar to namespace in other programming languages).

ES6 Module directory structure

I didn't find anything on Google but I'm wondering if there's a "best practise" of structuring an ES6 project in terms of directories and module exports.
Currently I do have two different ways in mind:
Using an index.js for every module and export everything:
app.js
modules/
ModuleName/
ModuleFile.js
index.js
ModuleFile.js would look something like export class ModuleFile { }, the index.js would be simply
export * from 'ModuleFile'
This makes it possible to import files with import {ModuleFile} from 'modules/ModuleName'. Readable, but requires an index.js for every module, even if the module has just one single file.
Second approach would be without using index.js files, but that would mean import statements would become slightly redundant import {ModuleFile} from 'modules/ModuleName/ModuleFile'.
Are there any best practises on this topic?
Your approach seems fine, I don't see a problem with it. In two different projects I've worked (different companies) it was the pattern used.
You could also put the ModuleFile.js content directly in index.js:
app.js
modules/
ModuleName/
index.js
Or create a file directly for a module:
app.js
modules/
moduleName.js
In cases only a "file" is necessary. The evident problem is that changes or the growth of the module may force this structure to change. There would also be an inconsistence in terms of structure with other modules.

What's the difference between import { compose } from 'recompose' vs import compose from 'recompose/compose [duplicate]

I'm reading the Material UI documentation, and it states:
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 cannot find any justification for why the use of default exports makes the build process faster or build output smaller.
My manager is asking us to refrain from using default exports, however a smaller build size is an important target for this project. I mentioned this quote by Material UI, and they said to find proof. I'd like some proof, please, as my attempts to compile it with Babel have shown default to be larger if anything.
The key thing is not whether the module has a default export or not, but the fact that you import a module that includes all the Material UI Components (the material-ui module) instead of the module that includes only the RaisedButton component (the material-ui/RaisedButton module).
To be absolutely clear: We should be using the module that only includes a single component, i.e. material-ui/RaisedButton.

Categories

Resources