@herowcode/utils
Overview
@herowcode/utils was built to solve a common pain in real-world web projects: the same utility functions (date formatting, slug generation, debounce/throttle, API wrappers, YouTube helpers, image compression) being copy‑pasted across multiple repositories. Every bug fix or improvement had to be replicated manually, which increased maintenance cost and left room for subtle inconsistencies.
I implemented a single, TypeScript‑first, tree‑shakable library that groups these helpers into focused modules (/api, /date, /string, /youtube, /files, /function, /array, /nextjs). Consumers can import from the root or use per‑module subpaths to keep bundles small. The build pipeline uses tsup to emit CJS, ESM and .d.ts declarations, with sideEffects: false configured to enable effective tree‑shaking in modern bundlers.
A key design goal was universal usage: the same library should work seamlessly in Node.js services and browser apps (including SSR). To achieve that, I rely on package.json conditional exports to expose environment‑specific implementations for sensitive modules like files and youtube. On top of that, the public API is shaped around production‑safe patterns, such as an apiClient that always returns { data, error } and encapsulates retry, backoff and token injection instead of throwing uncaught exceptions.
Today, @herowcode/utils acts as a shared foundation for multiple projects in the HerowCode ecosystem, reducing duplicated logic and allowing centralized fixes and improvements to propagate to all consumers through a single dependency update.
Key Differentiator
What makes @herowcode/utils different from “yet another utility belt” is its explicit focus on environment‑aware design and minimal bundle impact. Instead of shipping one monolithic bundle of helpers, it is structured around conditional exports and per‑module imports, so browser‑only and server‑only implementations can coexist without extra configuration on the consumer side.
Two areas in particular stand out: YouTube helpers and the HTTP client. The youtube module implements a robust three‑step fallback to fetch video metadata without requiring an API key: first it tries to parse the ytInitialPlayerResponse from the watch page HTML; if that fails, it falls back to YouTube’s oEmbed endpoint and then to NoEmbed. Requests are cached per video ID as in‑flight Promises so concurrent callers reuse the same network request. The apiClient follows a “never throw” philosophy: all operations resolve to { data, error }, with configurable retry/backoff for network and 5xx errors, async token injection and an onSignoutUnauthorized hook to centralize 401 handling.
If you need a compact, environment‑aware utility set that you can safely use in both Node and the browser, this library is deliberately optimized for that trade‑off instead of trying to be a giant catch‑all toolbox.
Architecture
- /api module: Typed HTTP client (
apiClient) with retry and exponential backoff, async token injection, optionalx-forwarded-forsupport and anonSignoutUnauthorizedcallback. Includes wrappers likeapiWrapperthat normalize async operations to{ data, error }. - /date module: Date/time helpers built on top of dayjs, including
formatDate,getRelativeTime,parseTimeSpentand timezone utilities likefixTimezoneOffset,getCurrentDateInUTCandgetDateInUTC. - /string module: String transformation utilities such as
camelCase,kebabCase,snakeCase,slugify,capitalize, truncation helpers, markdown‑to‑text conversion and time formatting (H:M:S). - /youtube module: Functions to
extractYouTubeId,generateYoutubeURL, validate links, retrieve thumbnails (getYoutubeThumbnail), fetch metadata with a three‑tier fallback (getYoutubeVideoInfo) and read video duration in the browser (getYoutubeVideoDurationvia the IFrame API). Includes in‑flight Promise caching per video ID. - /files module: Browser‑side utilities like
compressImage(offscreen canvas to WebP),downloadUrlandformatBytes, plus Node‑side helpers likefileExistsandfileDelete, exposed via conditional exports so each environment only sees relevant APIs. - /function module: Control‑flow helpers such as
debounce,throttleand a safetryCatchwrapper that turns thrown errors into{ data, error }results. - /array module: Helpers like
shuffle,uniqueandmarkdownToTextthat operate on collections and text content. - /nextjs module: An
OptimizedImagecomponent tailored for Next.js projects, withreactandnextas peer dependencies, focusing on better DX around image optimization.
Technical Highlights
- Conditional exports per entry point in
package.jsonso browser vs Node implementations are selected automatically for modules likefilesandyoutube, without custom bundler configuration. - Tree‑shakable package with
sideEffects: falseand a documented preference for per‑module imports (@herowcode/utils/date,@herowcode/utils/api), keeping bundle impact low. - tsup‑based build that produces CJS, ESM and
.d.tsdeclaration files, improving TypeScript developer experience and compatibility across different tooling ecosystems. - Error‑safe
apiClientdesign that always returns{ data, error }, includes configurable retry with backoff, supports async token injection and centralizes 401 handling viaonSignoutUnauthorized. - Three‑tier YouTube metadata strategy (
getYoutubeVideoInfo) combined with in‑flight Promise caching, enabling metadata retrieval without an API key and reducing redundant network calls. - Browser image compression via an offscreen canvas (
compressImage), generating WebP with configurable max width and quality, while keeping the Node build free of DOM dependencies through conditional exports. - Quality and automation tooling including Vitest + jsdom for tests, Biome for linting/formatting and GitHub Actions for CI, ensuring consistent builds and published artifacts.