Correct way to import lodash - javascript

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()

Related

import {fn1} from 'lib' vs import fn1 from 'lib'

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

Better way to import multiple 'export' with ES6 or TypeScript

I am using D3.js V4 with the module and I would like to import few modules into a single3` namespace. The code snippet below is my current solution, is there a better way to do so?
const d3 = Object.assign(
{},
require('d3-axis'),
require('d3-selection'),
require('d3-format')
)
So whenever I need anything, I just call something like below
d3.format('.5s')
// OR
d3.select(something)
Is there a nicer way to import everything into a single d3 namespace?
import multiple 'export' with ES6 or TypeScript
A typesafe way
import * as d3Axis from 'd3-axis';
import * as d3Selection from 'd3-selection';
export const d3 = {...d3Axis, ...d3Selection};
That said, d3 was written before TypeScript and does not support type safety in its API decisions.
More
Yes, you need to design for type safety, e.g. if your library uses direct array access it is inherently unsafe https://basarat.gitbooks.io/typescript/docs/types/index-signatures.html

How do i write this require as an es6 import statement

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();

ES6 module import group of files with individual exports

I would like to combine some modules into a single file that can be imported. These are local files and not part of an npm module.
Module Kitten (kitten.js)
export function Feed() {}
export function Play() {}
In my code I can access 'Feed' and 'Play':
// This works but I would like to avoid this due to my paths
import { Feed, Play } from './some/long/path/kitten.js'
// Then use it
Feed()
As I have many 'pets' I can contenate them in a master file - say pets.js
export * as Kitten from './some/long/path/kitten.js'
export * as Puppies from './some/long/path/puppies.js'
...
In my code I can then do:
import { Kitten, Puppies } from './pets'
// Then use it as
Kitten.Feed()
is it possible to have both a) the master pets file and b) call Feed() without doing Kitten.Feed()?
The following doesn't work as it's not a valid path. It's possible it would work as 'pets/Kitten' if it was an npm module - am not sure.
import { Feed, Play } from './pets/Kitten'
I was thinking something along the lines of:
import * as Pets from from './pets'
import { Feed, Play } from Pets.Kitten // or 'Pets/Kitten'
But clearly that doesn't work. I am wondering if it's at all possible.
I am using this in Node with Babel 6 and ES6 module loading. I see a lot of similar questions but they all use default exports which I am not using.
But that doesn't allow me to import selected functions.
Sure it does. The relative-path import works the same as module import. You can destructure the results just the same.
import { Play } from 'Pet/Puppy';
// is identical to
import { Play } from '../node_modules/Pet/Puppy';
If you take a look at the import syntax (s15.2.2), you can see that the from part expects a string. It doesn't care what's in the string, that's up to the module system (the browser, node, etc).
Ah.. object destructuring.. Forgot about that.
import { Kitten, Puppies } from './pets'
const {Feed, Play} = Kitten;
Thanks to https://stackoverflow.com/a/30132149/856498

Simplifying the `import as` syntax

I'm currently importing a few lodash functions with the following syntax:
import {cloneDeep as _cloneDeep, each as _each, size as _size} from 'lodash'
This works, but it's kind of annoying to have to specify each as variable renaming. Are there any shortcuts that would avoid this? I'd be happy to have all those methods inside an object as well, to simulate the functionality of when the entire lodash library is imported, e.g. _.cloneDeep, _.each, etc.
To clarify, I don't want to import the entire library. So I'm looking for a solution that still allows the modular importing of functions.
Since your goal is to avoid annoyance I suspect this may not be what you want but if you're very set on the consumer syntax and want individual importing for efficient packing or something you could always create an intermediary module.
This module will import the contents that you want and in your main code you can reference the intermediary module in the way you're hoping to.
As an example:
import {parse as _parse, join as _join} from 'path'
export var parse = _parse;
export var join = _join;
and in your main application,
import * as path from './custom-lib/path'
path.parse(...);
It involves an extra file which sucks, but you do only have to write it once.
I wouldn't necessarily call this a good solution, but I think this is the closest you're going to get to what you want with the current standards.
ECMA2015 has the option to import all into one object/container.
import * as _ from 'lodash'
then you can use it as before:
_.cloneDeep(), _.each(), etc...
You can import the whole lib as well as individual methods:
import _, { cloneDeep, each, isArray } from 'lodash';
_.isArray([]) // true
isArray([]) // true
When you do import x from 'y'; it will store the whole y module in the x variable.
Doing import {a, b, c} from 'y'; will just pull in the specific methods a, b, c of the module.
You can combine both types of import by just delimiting them with a comma as I did in the example.
Learn more at MDN's reference.

Categories