What is lodash?
"A modern JavaScript utility library delivering modularity, performance & extras."
index.js✅ copiedimport _ 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✅ copiedexport 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