Why you shouldn’t use Lodash

Javascript has made enormous strides the past few years and functions like findfindIndexmapfilter, and reduce are now standard. Before these innovations, when you had to work through collections or objects, the tools needed to make code cleaner and more functional were always easy to find in Lodash. Even though I think it definitely used to fulfil a useful purpose, I feel it is nowadays a bad practise to use.

Lodash, Angular

 

I used to work for a company that gave potential new colleagues a small coding assessment to take home. I was responsible for grading the Angular assessments and conducting the follow-up technical interview. The candidates were bound to have to make an array unique at some point. I occasionally encountered a developer who used functions from Lodash to perform this task that could have been done with a simple one-liner. Especially when these assessments were implemented in Angular, where they have Typescript and transpile processes built in, I felt this was very unneeded and then immediately started to doubt whether this would be a decent modern developer.

Let’s take a little closer look at the ramifications of using Lodash in an Angular project and why I feel it may not have a place in modern day development.

Bundle impact

I generated a fresh Angular 10 project and added an array of animals I found here. I added 6 duplicates to this array by randomly copying a few animals, and added a one-liner to make the array unique. The component is pretty clean and simple. Afterwards I made a production build, removed the 3rdpartylicenses.txt, and checked the size of the bundle (192K).

import { Component } from '@angular/core';@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})export class AppComponent {
  nonUniqueArray = [(...)]; // cut out to save space
  uniqueArray = [...new Set(this.nonUniqueArray)];
}// Command line
$ du -sh dist/angular-lodash
192K dist/angular-lodash

Next I added lodash to my package.json, and altered the component to use the uniq function instead. Following the same build process as above, we now ended up with a bundle size of 264K which is 38% larger than the previous one.

import { Component } from '@angular/core';
import { uniq } from 'lodash';@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})export class AppComponent {
  nonUniqueArray = [(...)]; // cut out to save space
  uniqueArray = uniq(this.nonUniqueArray);
}// Command line
$ du -sh dist/angular-lodash
264K dist/angular-lodash

Lodash adds 72K for a single function. Of course this doesn’t mean that every function you import will add an additional 72K and as you use more functions it will only be a little more. But be aware that uniq is not the only function which we can easily write ourselves.

webpack-bundle-analyzer
webpack-bundle-analyzer

If we perform a webpack-bundle-analyzer on this last build we get this output (screenshot). The hover may be hard to read in this image. It says “Stat size: 529 KB, Parsed size: 71KB, Gzipped size: 24Kb”.

This indeed confirms what we saw earlier. Lodash is a huge chunk of our build for using a single function that we can write ourselves in one line of code.

Performance

When we put aside the bundle size increase, which is by definition a decrease in performance, we can also look at how Lodash compares to solving this natively in vanilla JS. I used this piece of code to perform a crude benchmark:

const timer = (name) => {
  const start = new Date();
  return {
    stop: () => {
      const end = new Date();
      const time = end.getTime() - start.getTime();
      console.log(Timer: ${name}, finished in ${time} ms);
    },
  };
};const times = (x) => (f) => {
  if (x > 0) {
    f();
    times(x - 1)(f);
  }
};const timer1 = timer('Native unique');
times(10000)(() => [...new Set(nonUniqueArray)]);
timer1.stop();const timer2 = timer('Lodash uniq');
times(10000)(() => uniq(nonUniqueArray));
timer2.stop();// Results:
// Timer: Native unique finished in 105 ms
// Timer: Lodash uniq finished in 152 ms

We can see that Lodash performs 45% slower than using the native code. In terms of seconds (milliseconds) it is probably neglect-able, but why not take the small easy wins?

Alternatives to popular Lodash functions

I’ll list a few less intuitive operations that can be achieved easily without Lodash. Functions like find are intuitive enough for us, so I will not bother you with showing these. It’s just to give you an idea of how powerful Javascript is nowadays and how it has adapted.

uniq

const array = [1, 2, 3, 3, 4, 5, 1];// Lodash
_.uniq(array);// Native (option 1)
[...new Set(array)];// Native (option 2)
array.filter((item, index) => array.indexOf(item) === index);// Native (option 3)
array.reduce((unique, item) => unique.includes(item) ? unique : [...unique, item]);

compact

const array = [1, 0, 3, '', 4, false, true, 'item', undefined];// Lodash
_.compact(array);// Native
array.filter(Boolean);

first and rest

const array = ['first', 'second', 'third', 'last'];// Lodash
const firstItem = _.first(array);
const otherItems = _.rest(array);// Native
const [firstItem, ...otherItems] = array;

difference

const array1 = [1, 2, 3, 4, 5];
const array2 = [4, 10, 2];// Lodash
_.difference(array1, array2);// Native
const arrays = [array1, array2];
arrays.reduce((a, b) => a.filter(c => !b.includes(c)));

flattenDeep

const array = [1, [2, [3, [4]], 5]];// Lodash
_.flattenDeep(array);// Native
array.flat(Infinity);

There are many more examples of these, but my favourite resource for this is the “You-dont-need-Lodash-Underscore” repo found on Github.

Conclusion

We have seen that there are alternatives to Lodash’s functions in modern Javascript. We can now do the same in vanilla JS with smaller bundle sizes and higher performance.

While we’ve mainly looked at Lodash, this article does not apply only to this particular library, but also at libraries with similar functionality. The lesson that should be taken is that you should always write simple functions or processes yourself without relying on dependencies. If left-pad has taught us anything, it is that we should always rely on our own knowledge of structures and our own code.

If you found this article useful, don’t hesitate to share it on your Social Media Channels. I like writing about technical stuff, especially Angular related, so make sure to take a look at my other blogs on the Techspire website.

Who am I?

My name is Arjen Brandenburgh. I’m a senior frontend engineer and consultant working as Technical Lead for Techspire in the Netherlands. Working in the frontend field for almost 10 years and still loving it every single day. My main expertise lies with Angular. As a true geek I love to expand my knowledge and am proficient with Python, Ruby on Rails and AWS.

See all Techspire blogs?

https://techspire.nl/blogs/

See all Techspire news?

Follow our LinkedIn page: Techspire LinkedIn