@herowcode/utils
Visão Geral
@herowcode/utils nasceu para resolver um problema recorrente em projetos web: as mesmas funções utilitárias (formatar datas, gerar slugs, debouce/throttle, wrappers de API, helpers de YouTube, compressão de imagem) sendo copiadas e coladas entre vários repositórios. Cada correção ou melhoria precisava ser replicada manualmente, o que aumentava o risco de inconsistência e bugs difíceis de rastrear.
Implementei uma biblioteca única, escrita em TypeScript e pensada para ser tree‑shakable, que agrupa esses utilitários em módulos focados (/api, /date, /string, /youtube, /files, /function, /array, /nextjs). Os consumidores podem importar apenas o que precisam, seja a partir da raiz ou via subpaths, mantendo o bundle enxuto. O build é feito com tsup, gerando CJS, ESM e declarações .d.ts, com configuração de sideEffects: false para facilitar tree‑shaking.
Um ponto central foi garantir que a mesma lib funcionasse bem em Node.js e no browser. Para isso, usei exports condicionais no package.json, expondo implementações específicas para cada ambiente em módulos sensíveis, como files e youtube. Além disso, a API segue um padrão que favorece segurança em produção, como o apiClient que sempre retorna { data, error } e encapsula retry, backoff e injeção de token sem lançar exceções que quebrem a aplicação.
Hoje, @herowcode/utils funciona como base compartilhada para múltiplos projetos do ecossistema HerowCode, reduzindo duplicação de código e permitindo que correções e melhorias sejam centralizadas em um único pacote.
Diferencial Principal
O diferencial do @herowcode/utils é o foco explícito em dois eixos: uso universal (Node + browser) e impacto mínimo de bundle. Em vez de ser apenas “mais um pacote de helpers”, a biblioteca foi desenhada para suportar cenários reais de frontend moderno, SSR e serviços Node, usando exports condicionais para expor implementações específicas por ambiente sem exigir configuração manual do consumidor.
Outro ponto que se destaca é o módulo de YouTube e o cliente HTTP. Em youtube, implementei um fluxo de fallback em três níveis para obter metadados de vídeo sem depender de uma API key: primeiro tenta extrair o ytInitialPlayerResponse da página de watch, depois o oEmbed oficial e por fim o NoEmbed. As requisições são cacheadas por ID como Promises compartilhadas, evitando chamadas duplicadas quando múltiplas partes do sistema pedem o mesmo dado ao mesmo tempo. Já o apiClient segue um padrão “never throw”: todas as operações retornam { data, error }, com retry/backoff configurável e injeção assíncrona de token, o que simplifica bastante o tratamento de erro em aplicações grandes.
Arquitetura
- /api module: Cliente HTTP tipado (
apiClient) com retry, backoff, injeção assíncrona de token e callbackonSignoutUnauthorizedem 401, sempre retornando{ data, error }. Inclui wrappers comoapiWrapperpara padronizar operações assíncronas. - /date module: Utilitários de datas baseados em dayjs, como
formatDate,getRelativeTime,parseTimeSpente helpers de correção de timezone (fixTimezoneOffset,getCurrentDateInUTC,getDateInUTC). - /string module: Funções de transformação de string (como
camelCase,kebabCase,snakeCase,slugify,capitalize), truncamento, conversão de markdown para texto e formatadores de tempo (H:M:S). - /youtube module: Helpers para extrair ID (
extractYouTubeId), gerar URLs (generateYoutubeURL), buscar metadata com fallback em três fontes (getYoutubeVideoInfo), obter thumbnail (getYoutubeThumbnail), validar links e ler duração do vídeo no browser (getYoutubeVideoDurationvia IFrame API). - /files module: No browser, oferece
compressImage(conversão para WebP via canvas offscreen),downloadUrleformatBytes; em Node, expõe funções comofileExistsefileDeletevia exports condicionais. - /function module: Utilitários de controle de fluxo como
debounce,throttlee umtryCatchseguro que converte exceções em{ data, error }. - /array module: Funções como
shuffle,uniqueemarkdownToTextaplicadas a coleções. - /nextjs module: Componente
OptimizedImagepara projetos Next.js, comreactenextcomo peer dependencies, focado em DX e otimização de imagem.
Destaques Técnicos
- Uso de exports condicionais no
package.jsonpara escolher automaticamente implementações específicas de browser ou Node.js em módulos comofileseyoutube, sem esforço extra do consumidor. - Pacote tree‑shakable com
sideEffects: falsee incentivo a imports por submódulo (@herowcode/utils/date,@herowcode/utils/api), reduzindo o impacto no bundle final. - Build unificado com tsup, gerando CJS, ESM e declarações
.d.ts, facilitando integração com diferentes bundlers (Vite, Webpack, etc.) e garantindo boa DX em TypeScript. - Cliente HTTP
apiClientque nunca lança exceções, padronizando o retorno em{ data, error }, com retry/backoff configurável, injeção de token e callback para deslogar em 401. - Estratégia de fallback em três níveis para metadados de YouTube (
getYoutubeVideoInfo) com cache de Promises em andamento, evitando a necessidade de API key e prevenindo requisições duplicadas. - Utilitários de compressão de imagem no browser (
compressImage) usando canvas offscreen para gerar WebP com controle de qualidade e tamanho máximo, mantendo o build de Node livre de dependências de DOM via exports condicionais. - Infra de qualidade com Vitest + jsdom para testes, Biome para lint/format e GitHub Actions para CI, garantindo consistência no pacote publicado.