Skip to main content
Ben Nadel at cf.Objective() 2017 (Washington, D.C.) with: Raul Delgado
Ben Nadel at cf.Objective() 2017 (Washington, D.C.) with: Raul Delgado

Aggregating Cherry-Picked Lodash Methods In An Application Module In JavaScript

By
Published in Comments (6)

In an effort to build smaller and smaller JavaScript bundles with tools like Webpack, Rollup, and Browserify, web developers have started to forego full imports of libraries like Lodash; and, instead, are just cherry-picking (importing) individual methods out of the Lodash library. This way, when the bundler does its bundling, it only pulls in the isolated methods instead of the entire parent library. I think this is a noble effort. However, I rather dislike having my modules littered with esoteric variable names. And, to be honest, I miss having a single import for my utilities. As such, I've started to create a local application module that aggregates all of the cherry-picked Lodash methods.

NOTE: My examples happen to use TypeScript, but the theory should be the same regardless of technology choice.

Before aggregating Lodash methods, the use of cherry-picked methods might look something like this:

import find = require( "lodash/find" );
import without = require( "lodash/without" );

// ...
var item = find( collection, [ "id", id ] ),
// ...
collection = without( collection, item );
// ...
var item = find( collection, [ "name", name ] ),
// ...

As you can see, the find() and without() Lodash methods are being imported individually and then used unscoped in the body of the current module. This totally works. I just don't care for it. I find it harder to read because I don't get to leverage the years of practice I have seeing the "_" variable (and all that it entails). I also find it harder to comprehend how much of Lodash is being used by my application. At first, this may not seem important; however, if I want to factor-out my vendor imports using Webpack, understanding the points of Lodash integration is certainly important.

To find a happy middle-ground, where we walk away with smaller JavaScript bundles without sacrificing the organization of our utilities, I've started moving the cherry-pick imports to a local module I'm calling "lodash-extended" (inspired by Bluebird's "bludbird-extended" philosophy):

import find = require( "lodash/find" );
import random = require( "lodash/random" );
import range = require( "lodash/range" );
import without = require( "lodash/without" );

// Repackage and export the individual lodash functions.
// --
// *********************************************************************************** !!
// *********************************************************************************** !!
// IMPORTANT READ ME: When you add methods to this list, you must ALSO add them to the
// vendor file (main.vedor.ts). This way, as methods get added here, Webpack will know
// that they are not application-core methods and can factor them out into a versioned
// vendor module, which will help with HTTP caching.
// *********************************************************************************** !!
// *********************************************************************************** !!
export var _ = {
	find,
	random,
	range,
	without
};

As you can see, this Lodash-extended module is little more than glue around the cherry-picked Lodash methods. But, it forces me to understand the app/lodash integration in an important way (for bundle delineation). And, it brings me back to a place where I only need one import to get my utilities:

import { _ } from "./lodash-extended";

// ...
var item = _.find( collection, [ "id", id ] ),
// ...
collection = _.without( collection, item );
// ...
var item = _.find( collection, [ "name", name ] ),
// ...

To me, this is nice. I understand that this is totally subjective. But, this is what my brain likes. And, not only does it make it easier for me to consume the utilities, it also makes it easier for me to keep my bundles up-to-date because my lodash-extended module will mirror (in part) my vendor file:

// Import these libraries for their side-effects.
// --
// CAUTION: As you add more "import" statements to your application code, you will have
// to come back to this file and add those imports here as well (otherwise that imported
// content may get bundled with your main application bundle, not your vendor bundle.
import "lodash/find";
import "lodash/random";
import "lodash/range";
import "lodash/without";

And, of course, having a lodash-extended module gives me a nice place to add any additional functions - not provided by lodash - that would benefit my application in a generic way.

Smaller JavaScript bundles are nice. But, creating smaller bundles doesn't mean that we have to sacrifice packaging and established mental models. Aggregating cherry-picked Lodash methods in an application module gives us many of the normal benefits of a cohesive package with only a few lines of additional code. And, it gives us the added benefit of "just the right amount of friction" that will make it easier to keep our vendor files up-to-date.

Want to use code from this post? Check out the license.

Reader Comments

16 Comments

Note that you can skip the braces:

import _ from "./lodash-extended";

if you make `_` your default export:

export { _ as default };

15,848 Comments

@Šime,

Ah, good point. I haven't really dealt much with the "default" export in TypeScript; though, I have used the "module.exports" to set a single export in Node.js. What's cool about the "default" export, though, is that I _believe_ it can live along side other explicit exports.

15,848 Comments

@Suhas,

Thanks, I'll take a look at this - I've not seen it before. I basically only know enough Webpack to get things to compile for some very basic needs.

15,848 Comments

@Šime,

Ah, very cool - I didn't realize you could "export { x as default }". I really have to dig more into the default stuff in modules.

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel