Frontend Utility Library
Status: Draft
Assignee: Maiia Kuzmishyna
Problem
The codebase contains several hand-written code blocks that duplicate what a utility library could achieve in a well-tested and readable form.
Examples:
- Deep-copying objects is done via
JSON.parse(JSON.stringify(...))(deepCopyGeometryinPolygonUtils.ts). - Object filtering is implemented with a three-step
Object.keys+filter+reducepipeline (filterObject.ts). - Finding minimum value in a collection is handled by two separate
reducecalls withMath.min, (copyDrawingsForPlacingindrawing-utils.ts).
Moreover, there are a couple of future use cases that could be covered by a utility library.
- Deep-equals can be very useful for memoization - it allows to completely forgo memoization of object props if a deep equality function is supplied as a second argument to
React.memo(). - Debounce and throttle can be crucial for performance optimizations as they allow reducing the number of times an expensive computation executes. Debouncing and throttling are also known for being notoriously difficult to implement from scratch without mistakes.
Last but not least, there is one use case already covered by a specific utility library lodash which should also be considered when choosing a library.
- Range construction from zero to a given number in
BezierPolygon.tsx.
Constraints
- The library must be well-maintained, widely adopted, and have a stable release history.
- The library must cover all use cases listed in the Problem section: deep clone, deep equals, object omit, minBy, flatMap, debounce, throttle, and range.
- The library must be licensed under a permissive open-source license (e.g. MIT) to allow free use in this project.
- The library should support usage in typescript projects.
- Adding the library should not significantly increase bundle size.
Assumptions
- Implementing and maintaining utility functions from scratch requires disproportionate effort and introduces avoidable risk compared to adopting a well-tested library.
- Tree-shaking is effective in the Vite-based build pipeline, so unused library functions are excluded from the production bundle.
- The transitive presence of lodash in the dependency graph does not guarantee its API stability or continued availability; an explicit dependency should be declared for any library actively used in production code.
Solutions
Alternative A: lodash (by John-David Dalton)
Lodash is the most widely used JavaScript utility library, with over 60 million weekly npm downloads and a long release history dating back to 2012.
Declaring it as an explicit dependency therefore does not increase bundle size, and the import style import { range } from 'lodash-es' (lodash's ES module build) enables full tree-shaking via Vite.
Constraint fulfillment:
- Maintenance & adoption: actively maintained, 10k+ issues resolved, backed by the OpenJS Foundation.
- Use case coverage:
_.cloneDeep,_.isEqual,_.omit,_.minBy,_.flatMap,_.debounce,_.throttle,_.rangeare all available. - License: MIT.
- Typescript: TypeScript types are provided by the
@types/lodashpackage. - Bundle size: 80.6kB minified.
The frontend already uses it (in
BezierPolygon.tsx) without declaring it as an explicit dependency — it is pulled in transitively via@storybook/addon-controlsandvite-plugin-pwa. Declaring it as an explicit dependency therefore should not increase bundle size. Moreover, removing the usage inBezierPolygon.tsxwill not reduce bundle size either. Alternatively, a tree-shakable build of lodash could be imported (lodash-es).
Alternative B: es-toolkit (by Toss)
es-toolkit is a modern utility library designed as a drop-in alternative to lodash, built natively in TypeScript with tree-shaking as a first-class concern.
It covers all the required use cases: cloneDeep, isEqual, omit, minBy, flatMap, debounce, throttle, and range.
Benchmarks published by the authors show 2–3× smaller bundle sizes compared to lodash-es for equivalent imports, owing to leaner implementations without legacy browser support code.
Constraint fulfillment:
- Maintenance & adoption: actively maintained since 2024, growing adoption; backed by Toss (a large fintech company).
- Use case coverage: all required functions are available.
- License: MIT.
- Typescript: supported out-of-the-box.
- Bundle size: 28.3kB minified, supports tree-shaking.
es-toolkit is relatively new and has a smaller community and ecosystem.
Alternative C: Radash (by Ray Oelzer)
Radash is a TypeScript-first utility library with a focus on modern, readable functional patterns.
It covers most of the required use cases: clone (shallow), omit, min, flat, and a rich set of async utilities.
However, debounce and throttle are not part of Radash's API, and isEqual (deep equality) is absent as well, which means use cases constraint would not be met without supplementing Radash with another library.
Constraint fulfillment:
- Maintenance & adoption: actively maintained, however a smaller community than lodash or es-toolkit.
- Use case coverage - NOT FULFILLED: debounce, throttle, and deep equality are missing.
- License: MIT.
- Typescript: supported out-of-the-box.
- Bundle size: 11.8kB minified, supports tree-shaking.