Introdução
O texto a seguir é razoavelmente técnico e pressupõe um conhecimento básico de programação. Todo o código está disponível no meu repositório GitHub.
Esta é a primeira parte de uma série onde conto como este blog funciona hoje: estático, gerado no build, sem banco de dados e sem hacks para enganar o servidor do GitHub Pages.
Começamos pelo começo: por que um blog caseiro, e por que a primeira tentativa — uma SPA — não era a resposta.
O cenário de trabalho
Um site de portfólio com blog, hospedado no GitHub Pages desde o início e já com URL divulgada. O conteúdo do blog é escrito em Markdown e armazenado junto ao código do projeto.
Isso simplifica o fluxo: escrevo localmente, adiciono o arquivo ao repositório e publico. A proposta sempre foi simples — cada artigo deve gerar sua própria página automaticamente.
Algumas circunstâncias foram importantes para esta decisão:
- A hospedagem é feita pelo GitHub Pages e, portanto, não há banco de dados
- Já existia um SPA com meu cartão de visitas online
- Sem banco de dados é impossível algo como WordPress — são recursos demais para um simples blog
- Os arquivos em Markdown já fazem parte do meu fluxo de escrita (Obsidian)
A solução anterior: SPA com VueJS
O site era um SPA clássico: um único index.html carregando o JavaScript responsável por renderizar as páginas dinamicamente com base na URL.
Esse modelo funciona bem em praticamente qualquer ambiente — menos no GitHub Pages.
Particularidades do GitHub Pages
O GitHub Pages é excelente para conteúdo estático. Aplicações SPA não são páginas estáticas: dependem de um manejo no servidor para redirecionar as requisições ao index.html, sempre.
O problema aparece quando abro uma página direto, pela URL. Em vez de deixar o Vue tomar conta, o servidor tenta localizar um arquivo HTML correspondente à URL. Como não existe redirecionamento nativo para index.html, o resultado é erro 404.
Isso quebrava o fluxo completo de navegação.
O hack do 404.html
Para contornar, implementei um hack via 404.html, capturando a rota original e redirecionando manualmente:
/**
* public/404.html
*/
const resource = location.href
if (resource.includes('blog') || resource.includes('curriculo')) {
// Salva como `redirect` a página atual, que resultou em 404
sessionStorage.setItem('redirect', resource)
// Cria um elemento meta refresh para redirecionar
// o usuário à homepage, sem delay
const refresh = document.createElement('meta')
refresh.content = "0;URL='/'"
refresh.httpEquiv = 'refresh'
document.head.appendChild(refresh)
window.location.replace('/')
}
Do lado do index.html, outro trecho de script recuperava a rota salva e a restaurava na URL:
/**
* index.html
*/
const redirect = sessionStorage.getItem('redirect')
// Remove valor persistido e limpa histórico do usuário
if (redirect !== location.href) {
sessionStorage.removeItem('redirect')
history.replaceState(null, null, redirect)
}
Funciona? Sim. É bonito? Não. Frágil? Também.
Os problemas dessa abordagem
- SEO praticamente inexistente: nenhuma página possuía metadados adequados (OpenGraph,
<head>correto, etc). Para robôs e mecanismos de pesquisa, todas as páginas eram iguais: mesmo título, mesma descrição, mesma data de publicação. - Redirecionamento frágil: o
meta refreshcausa uma piscadela visível, o estado salvo emsessionStoragedepende do fluxo exato de sessão e qualquer mudança no servidor quebra o mecanismo. - Conteúdo dependente de JavaScript: sem JS, o visitante (ou o robô de busca) não vê nada além da casca vazia da aplicação.
O que vem a seguir
A solução foi simples e direta: em vez de depender do Vue no navegador, gerar tudo no build. É isso que veremos na segunda parte — a migração para o SSG com Vite.