I'm struggling to understand how to import CommonJS modules into an ESM syntax. I'm currently trying to work with the library url-metadata. url-metadata exposes a top-level export as a callable (which does not really conform to CommonJS, AFAIK):
const urlMetadata = require('url-metadata')
urlMetadata(URL, ...)
It's not possible to write:
import urlMetadata from 'urlMetadata'
since no default export is defined.
Instead, I have to write:
import * as urlMetadata from 'url-metadata'
Or:
import urlMetadata = require("url-metadata")
I tried to read up on module loading in Node but I'm still somewhat confused as to what is the correct way to do this and why.
import urlMetadata from 'url-metadata';
is syntactic sugar for
import { default as urlMetadata } from 'url-metadata';
Either will work fine.
The value assigned to module.exports in a CommonJS module is the default export.
See the Node.js docs.
I am trying to export my theme in my react app using `module.exports =
module.exports = {
defaultFontColor: "#282828",
name: "Planswell",
primary: primary,
deemphasizedPrimary: "#e7f6ee",
secondary: "#E4A432",
danger: "#DF5F2B"...}`
in my file whatever.js, and i try to import it in another file using import whatever from "themes/whatever.js";
All was working well, but i updated Babel, and am now getting the error Attempted import error: 'themes/whatever.js' does not contain a default export (imported as 'whatever').
What changed with Babel that caused this error? And how do I fix it?
If the only export in your whatever.js is
module.exports = {mod1, mod2, ...}
Then, assuming whatever is actually a module in your file, you should have never been able to import it using
import whatever from "themes/whatever.js";
The only way that would be possible is if in your whatever.js you did:
export default whatever;
Otherwise, you will have to destructure the import like so:
import {whatever, mod1, mod2, ...} from "themes/whatever.js";
Again, all this assumes that whatever is actually a module inside your whatever.js file e.g const whatever = () => {.... You don't make that part clear.
The error you're getting should help you guide your way. When using module.exports = {...} syntax, the default export is the object.
You should try importing specific exported properties of the module such as import { someModule } from 'themes/whatever.js'. Optionally you can use
import * as whatever from 'themes/whatever.js'
// Use it
whatever.myFunction()
Babel is pretty complex tool so I would check from which version you upgraded to and then looked at the change log to see what has changed. Babel has plethora of presets and plugins so it could be any combination, sorry no simple answer here.
To me it seems like perhaps you're using some different type of module.
Maybe you are using #babel/preset-env with combination of browserslist settings and you transpile to ES6 modules?
in your whatever.js you have exporting the as an object that contain your component so you have to export it like this
import {whatever} from "themes/whatever.js";
for your example to work you have to export your component without brackets
export {whatever}
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
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.
I had a pull request feedback below, just wondering which way is the correct way to import lodash?
You'd better do import has from 'lodash/has'.. For the earlier version
of lodash (v3) which by itself is pretty heavy, we should only import
a specidic module/function rather than importing the whole lodash
library. Not sure about the newer version (v4).
import has from 'lodash/has';
vs
import { has } from 'lodash';
Thanks
import has from 'lodash/has'; is better because lodash holds all it's functions in a single file, so rather than import the whole 'lodash' library at 100k, it's better to just import lodash's has function which is maybe 2k.
If you are using webpack 4, the following code is tree shakable.
import { has } from 'lodash-es';
The points to note;
CommonJS modules are not tree shakable so you should definitely use lodash-es, which is the Lodash library exported as ES Modules, rather than lodash (CommonJS).
lodash-es's package.json contains "sideEffects": false, which notifies webpack 4 that all the files inside the package are side effect free (see https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free).
This information is crucial for tree shaking since module bundlers do not tree shake files which possibly contain side effects even if their exported members are not used in anywhere.
Edit
As of version 1.9.0, Parcel also supports "sideEffects": false, threrefore import { has } from 'lodash-es'; is also tree shakable with Parcel.
It also supports tree shaking CommonJS modules, though it is likely tree shaking of ES Modules is more efficient than CommonJS according to my experiment.
Import specific methods inside of curly brackets
import { map, tail, times, uniq } from 'lodash';
Pros:
Only one import line(for a decent amount of functions)
More readable usage: map() instead of _.map() later in the javascript code.
Cons:
Every time we want to use a new function or stop using another - it needs to be maintained and managed
Copied from:The Correct Way to Import Lodash Libraries - A Benchmark article written by Alexander Chertkov.
You can import them as
import {concat, filter, orderBy} from 'lodash';
or as
import concat from 'lodash/concat';
import orderBy from 'lodash/orderBy';
import filter from 'lodash/filter';
the second one is much optimized than the first because it only loads the needed modules
then use like this
pendingArray: concat(
orderBy(
filter(payload, obj => obj.flag),
['flag'],
['desc'],
),
filter(payload, obj => !obj.flag),
If you are using babel, you should check out babel-plugin-lodash, it will cherry-pick the parts of lodash you are using for you, less hassle and a smaller bundle.
It has a few limitations:
You must use ES2015 imports to load Lodash
Babel < 6 & Node.js < 4 aren’t supported
Chain sequences aren’t supported. See this blog post for alternatives.
Modularized method packages aren’t supported
I just put them in their own file and export it for node and webpack:
// lodash-cherries.js
module.exports = {
defaults: require('lodash/defaults'),
isNil: require('lodash/isNil'),
isObject: require('lodash/isObject'),
isArray: require('lodash/isArray'),
isFunction: require('lodash/isFunction'),
isInteger: require('lodash/isInteger'),
isBoolean: require('lodash/isBoolean'),
keys: require('lodash/keys'),
set: require('lodash/set'),
get: require('lodash/get'),
}
I think this answer can be used in any project easily and brings the best result with less effort.
For Typescript users, use as following :
// lodash.utils.ts
export { default as get } from 'lodash/get';
export { default as isEmpty } from 'lodash/isEmpty';
export { default as isNil } from 'lodash/isNil';
...
And can be used the same way as importing lodash :
//some-code.ts
import { get } from './path/to/lodash.utils'
export static function getSomething(thing: any): any {
return get(thing, 'someSubField', 'someDefaultValue')
}
Or if you prefer to keep the _ to avoid conflicts (ex. map from rxjs vs lodash)
//some-other-code.ts
import * as _ from './path/to/lodash.utils'
export static function getSomething(thing: any): any {
return _.get(thing, 'someSubField', 'someDefaultValue')
}
UPDATE :
Seems like the right way to export is :
export * as get from 'lodash/get';
export * as isEmpty from 'lodash/isEmpty';
export * as isNil from 'lodash/isNil';
...
But there is a weird collision with #types/lodash, I've removed this type package because I would get this error :
Module '"/../project/node_modules/#types/lodash/cloneDeep"' uses
'export =' and cannot be used with 'export *'.ts(2498)
UPDATE :
After some digging, I've turned tsconfig.json feature esModuleInterop to true, and it allows me to do the following :
import get from 'lodash/get';
import isEmpty from 'lodash/isEmpty';
import isNil from 'lodash/isNil';
...
export { get, isEmpty, isNil, ... };
Note that this affects all your imports in your projects that has been defined as import * as lib from 'lib'. Follow the documentation to be sure it's suitable for you.
import { cloneDeep, groupBy } from 'lodash';
I think this is simpler when you don't need to convert array to lodash object by using _.
const groupData = groupBy(expandedData, (x) => x.room.name);
For those who want to keep using _ , then just import them like this:
import groupBy from 'lodash/groupBy';
import filter from 'lodash/filter';
import get from 'lodash/get';
window._ = {groupBy, filter, get};
I think the more cleaner way of importing lodash is just like this:-
import _ from 'lodash'
then you can use what ever you want just by using this underscore just like this:-
_.has()