1

[Pitch] Construí um widget de changelog em menos de 15KB usando Vanilla JS e Shadow DOM — e por quê não usei React

Fala, pessoal.

Acabei de lançar o Pushdock, uma ferramenta de changelog
para founders de SaaS. Quero compartilhar algumas decisões
técnicas que tomei durante o build que podem ser úteis
para quem está construindo widgets embeddáveis.


O CONTEXTO

Algumas ferramentas de changelog como o Beamer têm um widget
embeddável que os clientes instalam no próprio site.
O problema: alguns desses widgets podem pesar até 200KB. Isso impacta
diretamente o Core Web Vitals do site do cliente —
especialmente o LCP e o TBT.

Minha meta era diferente: menos de 15KB, zero dependências,
instalação com uma única linha de script.


POR QUE NÃO USEI REACT

A primeira decisão foi não usar React no bundle do widget.

React + ReactDOM sozinhos somam ~45KB gzipados.
Antes de escrever qualquer lógica do produto,
já estaria 3x acima da minha meta.

A solução foi Vanilla JS puro. Manipulação direta do DOM,
event listeners nativos, fetch API. Sem abstração,
sem overhead de reconciliação, sem virtual DOM.

O resultado: 11.8KB gzipados no momento do lançamento.


SHADOW DOM PARA ISOLAMENTO DE CSS

O segundo problema de widgets embeddáveis é o CSS.

Quando você injeta HTML no site de outra pessoa,
o CSS dela vaza para dentro do seu widget,
e o CSS do seu widget vaza para fora.
O resultado são estilos quebrados, z-index infinitos
e bugs impossíveis de reproduzir.

A solução é o Shadow DOM — uma feature nativa do browser
que cria um escopo completamente isolado:

`const host = document.createElement('div')
document.body.appendChild(host)

const shadow = host.attachShadow({ mode: 'open' })
shadow.innerHTML = `

/* CSS aqui não vaza para fora */ .widget { ... }
...
` `

O CSS dentro do shadow root não afeta o documento principal,
e o CSS do documento principal não afeta o shadow root.
Zero conflito, independente do site do cliente.

Suporte nos browsers: 96%+ globalmente.
Pode usar em produção sem preocupação.


INSTALAÇÃO COM UMA LINHA

A meta de UX era que o cliente instalasse o widget
sem precisar de npm, build step ou arquivo de configuração:

<script src="https://pushdock.app/changelog.js" data-project="seu-slug" data-position="bottom-right" data-accent="#6366f1"> </script>

O script carrega de forma assíncrona (não bloqueia o render),
lê os data attributes para configuração, cria o shadow DOM
e renderiza o widget. Tudo em menos de 50ms numa conexão 3G.


O QUE O PRODUTO FAZ

Além do widget, o Pushdock tem:

→ Página pública de changelog (SSG com Next.js 15)
→ Página pública de roadmap (SSG com Next.js 15)
→ Geração de posts com IA via OpenAI
→ Notificações por email para subscribers (double opt-in)
→ Integrações com Github Releases, Slack e Zapier (outras estão à caminho)
→ RSS feed automático
→ Flat pricing por conta — sem cobrança por MAU

É uma alternativa ao Beamer e AnnounceKit focada em
founders de SaaS que querem algo leve, simples e com
preço previsível.

Acabei de lançar hoje com zero clientes pagantes.
Se quiserem testar: https://pushdock.app


PERGUNTAS QUE ANTECIPO

P: Por que não usou um Web Component com Custom Elements?
R: Shadow DOM sem Custom Elements é suficiente para o
caso de uso e tem compatibilidade ligeiramente melhor.
Custom Elements adicionaria complexidade sem benefício real.

P: Como você faz o cache do widget?
R: O changelog.js / roadmap.js tem Cache-Control de 1 hora no CDN da Vercel.
A lista de posts da API tem revalidate de 60 segundos
no Next.js. O badge de "não lidos" usa localStorage
para persistir o timestamp da última visita.

P: Qual foi o maior desafio técnico?
R: Z-index. Mesmo com Shadow DOM, o widget precisa
aparecer acima de outros elementos do site do cliente.
A solução foi um z-index alto (9999) no host element
fora do shadow root, não dentro dele.


Aberto para perguntas técnicas sobre a implementação.
Se alguém tiver curiosidade sobre alguma parte específica
do código, posso detalhar nos comentários.

— Luiz
https://pushdock.app

Carregando publicação patrocinada...