How to import lodash on frontend applications without massively increasing your bundle size

How to import lodash on frontend applications without massively increasing your bundle size

Posted 2023-10-15

What is lodash?

"A modern JavaScript utility library delivering modularity, performance & extras."

index.js
✅ copied
import _ from 'lodash' _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor) // => [1.1, 2.3] _.groupBy([6.1, 4.2, 6.3], Math.floor); // => { '4': [4.2], '6': [6.1, 6.3] } _.groupBy(['one', 'two', 'three'], 'length'); // => { '3': ['one', 'two'], '5': ['three'] }

What is Vite?

  • Frontend build tool that is extremely quick to build your applications.

  • I'd recommend everyone using it if they get a chance.

  • Vite has built in tree shaking. But there are some cases where it doesn't work well. Lodash is one.

  • Spoiler: the 'issue' I'm raising is fixed by reading lodash's documentation better.

What is tree shaking?

  • A bundler technique to remove unused/dead code, leading to a smaller JS bundle size.

How I've been using lodash in frontend applications

import { isNil } from 'lodash' console.log(isNil(someValue))

And I assumed from lodash, only isNil would be in my JS that I serve to clients

Smallest lodash function to run this test with:

Very small function, to check if a value is undefined or null

function isNil(value) { return value == null; }

Impact of importing incorrectly (with vite)

All sizes are from running yarn build and looking at the built JS filesize on disk.

  • New Vite app - 143.41 kB
  • import _ from 'lodash' (and using _.isNil()) - 216 kB ❌
  • import * as _ from 'lodash' (and using _.isNil()) - 216 kB ❌
  • import {isNil} from 'lodash' - 216 kB ❌
  • import isNil from 'lodash/isNil' - 143.48 kB ✅
  • import {isNil} from 'lodash-es' - 143.45 kB ✅

Results in NextJS

Similar test, showing the bundle size changes.

NextJS handles lodash imports better.

  • New NextJS app (not using lodash) - 87.7 kB
  • import _ from 'lodash' (and using _.isNil()) - 114 kB ❌
  • import * as _ from 'lodash'- 114 kB ❌
  • import {isNil} from 'lodash' - 87.8 kB ✅
  • import isNil from 'lodash/isNil' - 87.8 kB ✅
  • import {isNil} from 'lodash-es' - 87.8 kB ✅

Vite's tree shaking works well normally

This isn't to knock Vite or lodash.

Here is an example where it works well.

fns.js
✅ copied
export const smallFn = () => 'x' export const largeFn = () => { const data =[ 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', // ... around 4000 more lines ].join() }

import {smallFn} from './fns'          ✅ 143 kB

import {largeFn} from './fns' ❌ 406 kB

This isn't a new issue

Lodash have this documented well on their website. And they offer solutions.

import isNil from 'lodash/isNil' // or import { isNil } from 'lodash-es'

You can also use tools like babel-plugin-lodash to automatically apply these.

In summary

If using lodash on frontend applications, double check your imports and bundle size.

Switch to the ESM lodash version at lodash-es

Or use the import isNil from 'lodash/isNil' style

Recommend adding eslint-plugin-lodash import rules to enforce it in your app

  • https://github.com/lodash/babel-plugin-lodash
  • https://github.com/jcoreio/jscodeshift-replace-lodash-method-packages
  • https://github.com/wix-incubator/eslint-plugin-lodash/tree/master

Subscribe to my
Full Stack Typescript Developer
newsletter

If you enjoyed my content and want more Full Stack Typescript content, then enter your email below.

I send a few links every couple of weeks, that I personally found useful from around the web.

Focusing on Build-tools, Typescript, NextJS, and also
engineering soft skills posts.

Welcome to my site and blog - Code Driven Development.

This is where I dive topics relating to modern software engineering - with a focus on Typescript, React, web accessibility and Agile practices

I pick topics that I think are interesting, that I think others might find interesting, or write up guides that I wish I had read before learning a topic.