Skip to content

Replace lodash with native JS equivalents#522

Open
Frank3K wants to merge 3 commits intofirebase:masterfrom
Frank3K:remove-lodash
Open

Replace lodash with native JS equivalents#522
Frank3K wants to merge 3 commits intofirebase:masterfrom
Frank3K:remove-lodash

Conversation

@Frank3K
Copy link

@Frank3K Frank3K commented Feb 26, 2026

Description

Removes lodash (and @types/lodash) as a dependency. All usages are replaced with native ES2020 equivalents: optional chaining, Array methods, Object.entries/spread, and typeof checks. A shared isPlainObject helper is extracted to src/utils/objectutils.js.

Why

Lodash was a sensible utility belt in the Node.js 4.x era, but the language has long since caught up. Every lodash function used in this codebase now has a direct, readable native equivalent available in Node 20+ (which is already the minimum required by our engines field).

Reasons to drop it:

  • CVE hygiene. Lodash has been the subject of multiple high-severity CVEs (prototype pollution, ReDoS).
  • Simpler mental model. Native Array.isArray, ?.superstatic?.headers, typeof x === "function", .endsWith(), Object.entries(), and spread syntax are things every JS developer knows without consulting lodash docs.
  • One fewer package to keep up with. No more scheduled bumps just to stay on the latest patch.

What changed

All lodash calls replaced with native equivalents across all files.

A shared isPlainObject helper is extracted to src/utils/objectutils.js to avoid duplication between src/responder.js and src/loaders/config-file.js.

Bundle size

Lodash itself remains in node_modules as a transitive dependency via glob-slasher, so the production install footprint is unchanged for now. I'm planning on creating a separate PR to replace glob-slasher, which is unmaintained for about 12 years, also to take a second look at #249.

@types/lodash is fully removed.

Verification

Tests are passing.

Removes lodash (and @types/lodash) as a dependency. All usages are
replaced with native ES2020 equivalents: optional chaining, Array
methods, Object.entries/spread, and typeof checks. A shared
isPlainObject helper is extracted to src/utils/objectutils.js.
].forEach((name) => {
exports[name] = function (spec, config) {
const mware = require("./" + _.kebabCase(name))(spec, config);
const mware = require("./" + name)(spec, config);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All names in the array are unchanged when passed through kebabCase.

);
}

module.exports = { isPlainObject };
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be done in Typescript instead?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Fixed in 3d5302e.

@bkendall
Copy link
Collaborator

I've slowly tilted at this similarly before - honestly, a nice PR :) Looks like something will need adjustment for the license check, but this is great!

Replaces the CommonJS module with a typed ES module export.
Adds a `val is Record<string, unknown>` type predicate so callers
get proper type narrowing when using `isPlainObject`.
@Frank3K
Copy link
Author

Frank3K commented Feb 28, 2026

Looks like something will need adjustment for the license check, but this is great!

Thanks! I've added the license in 5a1c257.

@Frank3K
Copy link
Author

Frank3K commented Feb 28, 2026

I'm planning on creating a separate PR to replace glob-slasher, which is unmaintained for about 12 years, also to take a second look at #249.

Created #524.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants