I'm trying to use lodash (v4.17.11) features with cherry picking import in my project. When I do this:
import {chain} from 'lodash';
and
chain([1,2,3]).take(1)
it works fine, however, if I change the import to:
import chain from 'lodash/chain';
the output is:
TypeError: (0 , _chain2.default)(...).take is not a function
Can someone please explain what's the mistake here
import chain from lodash/chain only works if there is a default export from the module.
If you want to import a particular named export - import {chain} from lodash/chain is the right way
See this - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
When you are using:
import {chain} from 'lodash/chain';
This treats the chain as named export not the default export from lodash/chain. But whenever you are point to a module lodash, in your case chain, module would be a default export rather than a named export. That is why when you use import chain from 'lodash/chain';, it brings the default export from the module.
chain would be a named export is you are importing it from the root of lodash as following:
import {chain} from 'lodash';
You should probably have a look at export and import in javascript and have a better understanding of it.
Related
I have referred all the questions in stackoverflow.
But none of the suggested why and when to use default export.
I just saw that default can be metioned "When there is only one export in a file"
Any other reason for using default export in es6 modules?
Some differences that might make you choose one over the other:
Named Exports
Can export multiple values
MUST use the exported name when importing
Default Exports
Export a single value
Can use any name when importing
This article does a nice job of explaining when it would be a good idea to use one over the other.
It's somewhat a matter of opinion, but there are some objective aspects to it:
You can have only one default export in a module, whereas you can have as many named exports as you like.
If you provide a default export, the programmer using it has to come up with a name for it. This can lead to inconsistency in a codebase, where Mary does
import example from "./example";
...but Joe does
import ex from "./example";
In contrast, with a named export, the programmer doesn't have to think about what to call it unless there's a conflict with another identifier in their module.¹ It's just
import { example } from "./example";
With a named export, the person importing it has to specify the name of what they're importing. They get a nice early error if they try to import something that doesn't exist.
If you consistently only use named exports, programmers importing from modules in the project don't have to think about whether what they want is the default or a named export.
¹ If there is a conflict (for instance, you want example from two different modules), you can use as to rename:
import { example as widgetExample } from "./widget/example";
import { example as gadgetExample } from "./gadget/example";
You should almost always favour named exports, default exports have many downsides
Problems with default exports:
Difficult to refactor or ensure consistency since they can be named anything in the codebase other than what its actually called
Difficult to analyze by automated tools or provide code intellisense and autocompletion
They break tree shaking as instead of importing the single function you want to use you're forcing webpack to import the entire file with whatever other dead code it has leading to bigger bundle sizes
You can't export more than a single export per file
You lose faster/direct access to imports
checkout these articles for a more detailed explanation:
https://blog.neufund.org/why-we-have-banned-default-exports-and-you-should-do-the-same-d51fdc2cf2ad
https://humanwhocodes.com/blog/2019/01/stop-using-default-exports-javascript-module/
https://rajeshnaroth.medium.com/avoid-es6-default-exports-a24142978a7a
With named exports, one can have multiple named exports per file. Then import the specific exports they want surrounded in braces. The name of imported module has to be the same as the name of the exported module.
// imports
// ex. importing a single named export
import { MyComponent } from "./MyComponent";
// ex. importing multiple named exports
import { MyComponent, MyComponent2 } from "./MyComponent";
// ex. giving a named import a different name by using "as":
import { MyComponent2 as MyNewComponent } from "./MyComponent";
// exports from ./MyComponent.js file
export const MyComponent = () => {}
export const MyComponent2 = () => {}
You can also alias named imports, assign a new name to a named export as you import it, allowing you to resolve naming collisions, or give the export a more informative name.
import MyComponent as MainComponent from "./MyComponent";
You can also Import all the named exports onto an object:
import * as MainComponents from "./MyComponent";
// use MainComponents.MyComponent and MainComponents.MyComponent2 here
One can have only one default export per file. When we import we have to specify a name and import like:
// import
import MyDefaultComponent from "./MyDefaultExport";
// export
const MyComponent = () => {}
export default MyComponent;
The naming of import is completely independent in default export and we can use any name we like.
From MDN:
Named exports are useful to export several values. During the import, one will be able to use the same name to refer to the corresponding value.
Concerning the default export, there is only a single default export per module. A default export can be a function, a class, an object or anything else. This value is to be considered as the “main” exported value since it will be the simplest to import.
There aren't any definitive rules, but there are some conventions that people use to make it easier to structure or share code.
When there is only one export in the entire file, there is no reason to make it named.
Also, when your module has one main purpose, it could make sense to make that your default export. In those cases you can extra named exports
In react for example, React is the default export, since that is often the only part that you need. You don't always Component, so that's a named export that you can import when needed.
import React, {Component} from 'react';
In the other cases where one module has multiple equal (or mostly equal) exports, it's better to use named exports
import { blue, red, green } from 'colors';
1st Method:-
export foo; //so that this can be used in other file
import {foo} from 'abc'; //importing data/fun from module
2nd Method:-
export default foo; //used in one file
import foo from 'blah'; //importing data/fun from module
3rd Method:-
export = foo;
import * as foo from 'blah';
The above methods roughly compile to the following syntax below:-
//all export methods
exports.foo = foo; //1st method
exports['default'] = foo; //2nd method
module.exports = foo; //3rd method
//all import methods
var foo = require('abc').foo; //1st method
var foo = require('abc')['default']; //2nd method
var foo = require('abc'); //3rd method
For more information, visit to Default keyword explaination
Note:- There can be only one export default in one file.
So whenever we are exporting only 1 function, then it's better to use default keyword while exporting
EASIEST DEFINITION TO CLEAR CONFUSIONS
Let us understand the export methods, first, so that we can analyze ourselves when to use what, or why do we do what we do.
Named exports: One or more exports per module. When there are more than one exports in a module, each named export must be restructured while importing. Since there could be either export in the same module and the compiler will not know which one is required unless we mention it.
//Named export , exporting:
export const xyz = () =>{
}
// while importing this
import {xyx} from 'path'
or
const {xyz} = require(path)
The braces are just restructuring the export object.
On the other hand , default exports are only one export per module , so they are pretty plain.
//exporting default
const xyz =() >{
};
export default xyz
//Importing
import xyz from 'path'
or
const xyz = require(path)
I hope this was pretty simple to understand, and by now you can understand why you import React modules within braces...
Named Export: (export)
With named exports, one can have multiple named exports per file. Then import the specific exports they want surrounded in braces. The name of imported module has to be the same as the name of the exported module.
// imports
// ex. importing a single named export
import { MyComponent } from "./MyComponent";
// ex. importing multiple named exports
import { MyComponent, MyComponent2 } from "./MyComponent";
// ex. giving a named import a different name by using "as":
import { MyComponent2 as MyNewComponent } from "./MyComponent";
// exports from ./MyComponent.js file
export const MyComponent = () => {}
export const MyComponent2 = () => {}
Import all the named exports onto an object:
// use MainComponents.MyComponent and MainComponents.MyComponent2 here
import * as MainComponents from "./MyComponent";
Default Export: (export default)
One can have only one default export per file. When we import we have to specify a name and import like:
// import
import MyDefaultComponent from "./MyDefaultExport";
// export
const MyComponent = () => {}
export default MyComponent;
Note: The naming of import is completely independent in default export and we can use any name we like.
Here's a great answer that explains default and named imports in ES6
I am importing a few functions from lodash and my coworker tells me that it's better to import each function separately than to import them as a group.
Current method:
import {fn1, fn2, fn3} from 'lodash';
Preferred method:
import fn1 from 'lodash/fn1';
import fn2 from 'lodash/fn2';
import fn3 from 'lodash/fn3';
Her reasoning is that latter imports less code, as it won't import the entire lodash library.
Is that the case?
What you want (and what is preferred) is called tree shaking:
Tree-shaking is the process of
removing unused code during the bundle process.
The correct way to do this and utilize the tree shaking is:
import foo from 'lodash/foo' // <-- only import `foo`
This will not tree-shake:
import { foo } from 'lodash'
nor will, obviously this:
import _ from 'lodash'
Support for this syntax was implemented in Lodash v4.
You can read more here
Based on the sources I can find, import x from y; imports the default export from y, calling it x in your file.
So your preferred method is importing the default export 3 times, with 3 different variable names...
Is the preferred method working in production?
Sources:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
https://medium.com/javascript-in-plain-english/javascript-modules-for-beginners-56939088f7d9
I do believe that import {fn1, fn2, fn3} from 'lodash'; is the correct way to import different exports of module, however, I think it could be better to use this way
import {
fn1,
fn2,
fn3
} from 'lodash';
Since it is easier to remove any of them if it no longer requires
In many npm modules I recently installed (eg. #material-ui/core) there are three ways to import the same React component:
import { AppBar } from '#material-ui/core'
import AppBar from '#material-ui/core/AppBar/AppBar'
import AppBar from '#material-ui/core/es/AppBar/AppBar'
In which scenario should I use variant 3 / es6 exported files?
If tree-shaking / dead code elimination works in webpack and the npm module. Should I rather use variant 1 (named import) instead of variant 2 (default export)?
There are two types of export:
1) Named export that is you export something like:
// exports a function declared earlier
export { myFunction };
// exports a constant
export const FOO = "foo";
if you want to import these, then syntax would be like:
import {FOO, myFunction} from './file';
2) Default export that is you export something like:
export default function() {}
you can rename your function, class to any name you want when you import, and its syntax would be like:
import myFunction from './file';
NOTE: You can have multiple named export in single file but you can not have multiple default export in single file.
For more detail check out this link: https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export
The main difference is how that library is exporting the modules.
When you do import AppBar from '#material-ui/core/AppBar/AppBar', this means that #material-ui/core/AppBar/AppBar is exporting a single object with export default AppBar.
And you're expected to imported as you did. However you're not limited to export a single default export from your module.
For example with React exposes the main object (i.e. React which is again being exported as default) that has all the properties you may want to use. But with the import syntax from ES6, you can import a specific property/function from that module(e.g. import { Component } from 'react'; which is exported as export class Component...)
I hope that's clear!
What is the difference between importing stuff from material-ui like this
import { Paper } from '#material-ui/core'
vs. like this, which works exactly the same way in my Webpack setup:
import Paper from '#material-ui/core/Paper'
Is any of these methods of importing, costly in terms of the resulting bundle size?
Note:
I am using this in a project that was bootstrapped with Create-React-App and the Create-Reac-App that I am using uses Webpack v3.5.1
import { something } from 'test-m' implies that, test-m has a named export on it, i.e:
module.exports = {
something: 'other string'
}
or even, on the es6 syntax:
export const something = 'other string'
--
import something from 'test-m' => implies that test-m has a default exports, i.e:
module.exports = 'other string'
or with es6 syntax export default 'other string'
How this affects bundling? Well, named exports is the way to go. Why?
Named exports imports only what is necessary from each module, so by using named exports, bundlers can tree-shake the module and take out from that module only what is necessary. This process decreases by a lot the size of the final module. In comparison to default exports, bundlers would pull to the chunk the whole module, despite you using one or all features that module provides.
TL;TR: named exports === lower bundle size.
In the case of import { Paper } from '#material-ui/core' you are importing the Paper named export from #material-ui/core module which contains other named exports.
In the case of import Paper from '#material-ui/core/Paper' you are importing the default export from #material-ui/core/Paper module which contains only Paper and exports it as default.
Some libraries have this approach of exposing both the main script with named exports and the individual modules for each function. For instance, Lodash. You can do both import { find } from 'lodash' and import find from 'lodash/find'. In both cases you will get the same find function.
Regarding pros, depending on the bundler configuration and the modules system used by the library, this: import { Paper } from '#material-ui/core' may not be tree-shaked and you will end up with the whole '#material-ui/core' in your bundle.
This: import Paper from '#material-ui/core/Paper' for sure will always only add Paper to your bundled code.
The first import will import the default class export. Whereas the second import imports only the exported function/object. This is quite a common difference when importing for Jest tests in react.
Take an example of a redux connected component:
export class ReduxConnect {
render(){
return (<h1> Some component </h1>);
}
}
export const mapStateToProps = state => ({
something: state.something
});
export default connect(mapStateToProps)(ReduxConnect);
Doing import ReduxConnect will import the default import, defined at the bottom which exports the redux connected component. Whereas import {ReduxConnect, mapStateToProps} would give you the option to export objects/functions individually from the class. In this case the difference would be between importing the redux connected component vs the pure component itself.
Problem
I have this require statement
require('smoothscroll-polyfill').polyfill();
But I would like to write it as an es6 import statement
I have tried
import 'smoothscroll-polyfill';
and
import * as 'smoothscrollPolyfill' from 'smoothscroll-polyfill';
But cant get it to work correctly, so what is the correct way to import a package like this?
You'd do it in two parts, first the import, then the function call:
If polyfill itself is a named export and it doesn't care what this is when it's called:
import {polyfill} from 'smoothscroll-polyfill';
polyfill();
(And you've now confirmed that was the case.)
For completeness, before the above was confirmed, I also listed these other possibilities which may be useful for others in future:
If polyfill is a property on the default export (rather than its own named export), then we import the default (no {} in the import statement) and then use its property:
import smoothScrollPolyFill from 'smoothscroll-polyfill';
const polyfill = smoothScrollPolyFill.polyfill();
If the smoothScrollPolyFill part is a named export and polyfill is a property on it, then we'd use the {} on import:
import {smoothScrollPolyFill} from 'smoothscroll-polyfill';
const polyfill = smoothScrollPolyFill.polyfill();
using import {} from '...' instead.
import {polyfill} from 'smoothscroll-polyfill';//ref polyfill from 'smotthscroll-polyfill'
polyfill();//ref a method,so you must call it after imported.
Assuming you're using Babel or something similar to provide compatibility between CommonJS modules and ES6 modules, the syntax would look something like this:
import smoothscrollPolyfill from "smoothscroll-polyfill";
smoothscrollPolyfill.polyfill();