Blog author's portrait
Artur Tagisow
Vue dev from Eastern Poland

yarn add webpack-cli lodash lodash-es - comparing bundle sizes with different import types

2020-11-28 01:14:00

You know that time when you think —

heh, let’s check out the bundle size of my work project

and run npm run build instead of npm run serve like always?
Output of vue-cli-service build - a 6MB bundle
That’s a 6MB bundle!

Through the very handy vue ui, I checked out which dependencies baloon this the most:

List of dependencies that make up the 6MB bundle - moment 600KB, ramda 600KB, lodash 530KB

This is hilarious because the enteriety of lodash weighs 70KB.

OK, but what do the occurences of import XYZ from 'lodash' look like in the project?

  13 results - 12 files
  import * as _ from 'lodash';
  import _ from 'lodash';
  import _ from 'lodash';
  import _ from 'lodash';
  import _ from 'lodash';
  import _ from 'lodash';
  import { cloneDeep } from 'lodash';
  import _ from 'lodash';
  import _ from 'lodash';
  import { debounce } from 'lodash';
  import _ from 'lodash';
  import { debounce } from 'lodash';
  import { MergeWithCustomizer } from 'lodash';

Is one way of importing lodash better than the other?
YES

You see, the import {} from 'lodash' are mine.
My thought process:

import _ from 'lodash' //>:( bad!! imports whole 70KB of lodash!
_.debounce(() => {}, 100);

import {debounce} from 'lodash' // genius, only probably 2KB added to bundle
debounce(() => {}, 100)

It’s WRONG

Then which way is best?

There are 4 most common ways of importing lodash:

  1. import * as _ from 'lodash'
  2. import _ from 'lodash'
  3. import {something} from 'lodash'
  4. import something from 'lodash/something'

and two versions of lodash:

  1. lodash
  2. lodash-es

I’m going to install just webpack, lodash, lodash-es and we’ll see.

Firing up webpack

Case 1

import debounce from 'lodash/debounce'
debounce(() => {console.log('go')}, 1000)
lodash-test ➤ yarn build
yarn run v1.22.4
$ webpack
[webpack-cli] Compilation finished
asset main.js 2.98 KiB [compared for emit] [minimized] (name: main)
runtime modules 878 bytes 4 modules
modules by path ./node_modules/lodash/*.js 13 KiB
  ./node_modules/lodash/debounce.js 5.96 KiB [built] [code generated]
  ./node_modules/lodash/isObject.js 733 bytes [built] [code generated]
  ./node_modules/lodash/now.js 520 bytes [built] [code generated]
  ./node_modules/lodash/toNumber.js 1.54 KiB [built] [code generated]
  ./node_modules/lodash/_root.js 300 bytes [built] [code generated]
  ./node_modules/lodash/isSymbol.js 682 bytes [built] [code generated]
  ./node_modules/lodash/_freeGlobal.js 173 bytes [built] [code generated]
  ./node_modules/lodash/_baseGetTag.js 792 bytes [built] [code generated]
  ./node_modules/lodash/isObjectLike.js 614 bytes [built] [code generated]
  ./node_modules/lodash/_Symbol.js 118 bytes [built] [code generated]
  ./node_modules/lodash/_getRawTag.js 1.11 KiB [built] [code generated]
  ./node_modules/lodash/_objectToString.js 565 bytes [built] [code generated]
./src/index.js 81 bytes [built] [code generated]
webpack 5.8.0 compiled successfully in 441 ms
Done in 1.31s.


Case 2

import _ from 'lodash'
_.debounce(() => {console.log('go')}, 1000)
lodash-test ➤ yarn build
yarn run v1.22.4
$ webpack
[webpack-cli] Compilation finished
asset main.js 69.2 KiB [emitted] [minimized] (name: main) 1 related asset
runtime modules 1000 bytes 5 modules
cacheable modules 530 KiB
  ./src/index.js 67 bytes [built] [code generated]
  ./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.8.0 compiled successfully in 2888 ms
Done in 3.65s.

Case 3

import * as _ from 'lodash'
_.debounce(() => {console.log('go')}, 1000)
lodash-test ➤ yarn build
yarn run v1.22.4
$ webpack
[webpack-cli] Compilation finished
asset main.js 69.2 KiB [compared for emit] [minimized] (name: main) 1 related asset
runtime modules 1000 bytes 5 modules
cacheable modules 530 KiB
  ./src/index.js 72 bytes [built] [code generated]
  ./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.8.0 compiled successfully in 2845 ms
Done in 3.57s.

Case 4

import {debounce} from 'lodash'
debounce(() => {console.log('go')}, 1000)
lodash-test ➤ yarn build
yarn run v1.22.4
$ webpack
[webpack-cli] Compilation finished
asset main.js 69.2 KiB [emitted] [minimized] (name: main) 1 related asset
runtime modules 1000 bytes 5 modules
cacheable modules 530 KiB
  ./src/index.js 74 bytes [built] [code generated]
  ./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.8.0 compiled successfully in 2748 ms
Done in 3.46s.


lodash-es

Case 1

import debounce from 'lodash-es/debounce'
debounce(() => {console.log('go')}, 1000)
lodash-test ➤ yarn build
yarn run v1.22.4
$ webpack
[webpack-cli] Compilation finished
asset main.js 2.16 KiB [emitted] [minimized] (name: main)
orphan modules 13 KiB [orphan] 12 modules
runtime modules 221 bytes 1 module
./src/index.js + 12 modules 13.1 KiB [built] [code generated]
webpack 5.8.0 compiled successfully in 437 ms
Done in 1.17s.

Case 2

import _ from 'lodash-es'
_.debounce(() => {console.log('go')}, 1000)
yarn run v1.22.4
$ webpack
[webpack-cli] Compilation finished
asset main.js 81.7 KiB [emitted] [minimized] (name: main) 1 related asset
orphan modules 606 KiB [orphan] 632 modules
runtime modules 962 bytes 4 modules
cacheable modules 576 KiB
  ./src/index.js + 610 modules 572 KiB [built] [code generated]
  ./node_modules/lodash-es/isBuffer.js 1.09 KiB [built] [code generated]
  ./node_modules/lodash-es/stubFalse.js 278 bytes [built] [code generated]
  ./node_modules/lodash-es/_root.js 298 bytes [built] [code generated]
  ./node_modules/lodash-es/_nodeUtil.js 993 bytes [built] [code generated]
  ./node_modules/lodash-es/_freeGlobal.js 171 bytes [built] [code generated]
  ./node_modules/lodash-es/_cloneBuffer.js 1.03 KiB [built] [code generated]
webpack 5.8.0 compiled successfully in 4629 ms
Done in 5.42s.

Case 3

import * as _ from 'lodash-es'
_.debounce(() => {console.log('go')}, 1000)
lodash-test ➤ yarn build
yarn run v1.22.4
$ webpack
[webpack-cli] Compilation finished
asset main.js 2.16 KiB [emitted] [minimized] (name: main)
orphan modules 609 KiB [orphan] 638 modules
runtime modules 221 bytes 1 module
./src/index.js + 12 modules 13 KiB [built] [code generated]
webpack 5.8.0 compiled successfully in 1840 ms
Done in 2.67s.

Case 4

import {debounce} from 'lodash-es'
debounce(() => {console.log('go')}, 1000)
lodash-test ➤ yarn build
yarn run v1.22.4
$ webpack
[webpack-cli] Compilation finished
asset main.js 2.16 KiB [emitted] [minimized] (name: main)
orphan modules 609 KiB [orphan] 638 modules
runtime modules 221 bytes 1 module
./src/index.js + 12 modules 13 KiB [built] [code generated]
webpack 5.8.0 compiled successfully in 1766 ms
Done in 2.56s.

Summary

If comparing in absolutes, lodash-es is better.

The webpack setup I used for testing is here: https://github.com/sethidden/lodash-test