Skip to content

cytoscape-style: drop lodash for small local memoize and throttle - #15

Merged
adamjohnwright merged 2 commits into
mainfrom
perf/drop-lodash
Oct 13, 2026
Merged

adamjohnwright merged 2 commits into
mainfrom
perf/drop-lodash

Conversation

@adamjohnwright

Copy link
Copy Markdown
Contributor

ngx-reactome-cytoscape-style imported four functions from lodash. lodash is CommonJS, so those named imports carried the whole library (about 73 KB) into every app bundle that uses this one. That includes WebsiteAngular's embeddable diagram, which is over its size target (reactome/WebsiteAngular#356).

lodash Replaced by
isArray, isNumber Array.isArray, typeof x === 'number'. This is what lodash's versions do.
memoize util/memoize.ts. It keys on the first argument or on a resolver, with a Map as cache, since style.ts and clearDrawersCache clear it.
throttle util/throttle.ts, a port of lodash's algorithm: debounce with leading, trailing and maxWait = wait.

Held to lodash's behaviour. memoize.spec.ts and throttle.spec.ts run the same checks against lodash's functions and ours. The throttle spec compares the two call for call: five hand-picked call sequences and four seeded irregular ones, the way render events arrive.

  • A simpler fixed-window throttle failed it. For calls at 0, 499, 501 and 1200, lodash runs at 0, 500, 1001 and 1200, while the simple version ran at 0, 500, 1000 and 1500.
  • That's why it's a port. It now matches on all nine sequences.

lodash is no longer a peer dependency of this library. ngx-reactome-diagram still uses it and keeps its own dependency. The built fesm2022 bundle has no lodash import.

Checks: tests 29/29, and preflight passes (lockfile, format, libraries, lint, dead code, tests, demo build, pack).

🤖 Generated with Claude Code

Adam Wright and others added 2 commits October 13, 2026 04:40
lodash is CommonJS, so the library's named imports of it carried the whole
of lodash (about 73 KB) into every app bundle that used the library --
including WebsiteAngular's embeddable diagram, which is over its size
target (reactome/WebsiteAngular#356). Four functions were used:

- isArray, isNumber: Array.isArray and typeof === 'number' (what lodash's do).
- memoize: util/memoize.ts, keyed on the first argument or a resolver, with a
  Map as `cache` (callers clear it). memoize.spec.ts runs the same checks
  against lodash's and ours.
- throttle: util/throttle.ts, a port of lodash's algorithm (debounce with
  leading, trailing, maxWait = wait). throttle.spec.ts compares the two call
  for call over fixed and seeded irregular timings; a simpler fixed-window
  version failed it ("a call just after a window": lodash runs at 1001 and
  1200, it ran at 1000 and 1500), which is why it is a port.

lodash is no longer a peer dependency of ngx-reactome-cytoscape-style.
ngx-reactome-diagram still uses it and keeps its own dependency.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@adamjohnwright

Copy link
Copy Markdown
Contributor Author

Review (subagent, adversarial): no defects. The throttle port matches lodash 4.18.1's debounce/throttle branch for branch (first call, maxWait branch, shouldInvoke incl. sinceCall < 0, remainingWait, trailing edge, re-entrancy), and memoize matches lodash's keying (SameValueZero, object identity, cache.has so undefined results are remembered). The specs were broken four ways on purpose and caught each. One gap closed in the latest commit: the spec now also covers the clock going backwards (shown failing with the sinceCall < 0 check removed) and fn calling the throttled function again. Noted, not changed here: CROSS is keyed only on size and never cleared, so after a theme change the cross keeps its old colours -- as it did with lodash.

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.

1 participant