Have you ever taken a break from programming, only to return and wrestle with package updates, outdated dependencies, or broken code? This issue often arises if your project heavily relies on a multitude of libraries and packages. In such instances, you might want to consider reducing the number of external imports your project utilizes.
We encountered this issue recently and perceived it as an opportunity to write a small helper utility that could replace a popular package.
Today, I'll be replacing a widely-used package called clsx
(or classnames, etc) with a tiny function.
Planning
With clsx
, you can pass a mix of strings, objects, arrays, and it consistently resolves to a string of classes to be used in your elements. If you're using a framework like Tailwind, where everything is accomplished through classes, you likely depend heavily on this function.
However, my colleagues and I rarely used it with objects.
Instead of this:
clsx('base', undefined, ['more', 'classes'], {
'bg-red': hasError,
'pointer-events-none': !isEnabled,
'font-semibold': isTitle,
'font-normal': !isTitle,
})
// Result: "base more classes bg-red font-normal"
We prefer an API like:
cx('base', undefined, ['more', 'classes'],
hasError && 'bg-red',
isEnabled || 'pointer-events-none',
isTitle ? 'font-semibold' : 'font-normal'
)
// Result: "base more classes bg-red font-normal"
In fact, with the addition of the || operator, the final API proved to be even better suited for our needs.
The implementation
The final version of our function, which is just a few lines of code, accepts an array of unknown values, filters for strings, joins them with a space, and trims any leading or trailing whitespace:
function cx(...args: unknown[]) {
return args
.flat()
.filter(x => typeof x === 'string')
.join(' ')
.trim()
}
Conclusion
Think twice before adding yet another package. Sometimes, all you need are a few lines of code - which might be fewer than the additions made to your package-lock.json at the end of the day. Always consider whether you can achieve the same functionality with a simpler, custom solution.