Construindo um Blog Moderno: Do Conceito à Implementação
Como desenvolvi um blog pessoal usando Astro, Tailwind CSS e técnicas modernas de desenvolvimento, com auxílio de IA para otimização e testes
Há algumas semanas, decidi criar um novo blog pessoal. Não apenas como uma vitrine para meus projetos, mas como um laboratório para experimentar tecnologias modernas e documentar minha jornada no desenvolvimento. O resultado foi muito além do que imaginei inicialmente.
Motivação e Objetivos
Por que um novo blog?
O projeto nasceu de duas necessidades principais:
- Posicionamento profissional: Queria um espaço para compartilhar conhecimentos sobre dados, engenharia de software e telemetria de forma mais estruturada
- Desenvolvimento pessoal: Precisava de um projeto paralelo interessante para experimentar novas tecnologias e manter-me atualizado
Objetivos técnicos
- Performance excepcional (Core Web Vitals otimizados)
- Design moderno e responsivo
- Experiência de desenvolvimento fluida
- SEO otimizado para melhor visibilidade
- Facilidade de manutenção e extensibilidade
Stack Tecnológica Escolhida
Astro como Foundation
Optei pelo Astro v4.16.19 como gerador de sites estáticos por várias razões técnicas:
// astro.config.mjs
export default defineConfig({
integrations: [
tailwind(),
mdx(),
sitemap()
],
markdown: {
shikiConfig: {
theme: 'github-dark',
wrap: true
}
},
site: 'https://meublog.dev'
});
Vantagens do Astro:
- Islands Architecture: JavaScript hidratado apenas onde necessário
- Zero JS por padrão: Performance superior com loading mínimo
- Flexibilidade: Suporte a React, Vue, Svelte quando necessário
- Built-in optimizations: Lazy loading, code splitting automático
Tailwind CSS para Design System
/* tailwind.config.cjs */
module.exports = {
theme: {
extend: {
colors: {
primary: {
50: '#eff6ff',
600: '#2563eb',
// Palette personalizada indigo/purple
}
},
typography: {
DEFAULT: {
css: {
maxWidth: 'none',
// Customizações para melhor legibilidade
}
}
}
}
}
}
Por que Tailwind:
- Consistência: Design system coeso em toda aplicação
- Performance: CSS otimizado com purging automático
- Experiência de Desenvolvimento: Autocomplete excelente no VS Code
- Customização: Fácil extensão do tema base
TypeScript para Type Safety
// src/lib/posts.ts
interface PostFrontmatter {
title: string;
description?: string;
date: string;
category: string;
tags?: string[];
featured?: boolean;
readingTime?: string;
}
export function getAllPosts(): Array<{
url: string;
frontmatter: PostFrontmatter;
}> {
// Implementação type-safe para coleta de posts
}
Arquitetura e Estrutura
Organização de Arquivos
src/
├── components/ # Componentes reutilizáveis
│ ├── AuthorBio.astro
│ ├── CategoryBadge.astro
│ └── ThemeToggle.astro
├── layouts/ # Layouts base
│ ├── BaseLayout.astro
│ └── PostLayout.astro
├── pages/ # Rotas da aplicação
│ ├── index.astro
│ ├── posts.astro
│ └── [slug].astro
├── content/ # Conteúdo em MDX
│ ├── posts/
│ └── notes/
├── lib/ # Utilities e helpers
└── styles/ # Estilos globais
Sistema de Componentes
Desenvolvi componentes modulares e reutilizáveis:
---
// CategoryBadge.astro
export interface Props {
name: string;
size?: 'sm' | 'md' | 'lg';
variant?: 'default' | 'outlined';
}
const { name, size = 'md', variant = 'default' } = Astro.props;
---
<span
class={`
inline-flex items-center rounded-full font-medium
${size === 'sm' ? 'px-2 py-1 text-xs' : 'px-3 py-1.5 text-sm'}
${variant === 'outlined'
? 'border border-indigo-200 text-indigo-700'
: 'bg-indigo-100 text-indigo-800'
}
`}
>
{name}
</span>
Funcionalidades Implementadas
Sistema de Busca e Filtros
Implementei um sistema de busca client-side otimizado:
// Busca em tempo real com debounce
function setupSearch() {
const searchInput = document.getElementById('search');
const articles = Array.from(document.querySelectorAll('[data-searchable]'));
let debounceTimer;
searchInput.addEventListener('input', (e) => {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
filterArticles(e.target.value, articles);
}, 300);
});
}
function filterArticles(term, articles) {
const normalizedTerm = term.toLowerCase().trim();
articles.forEach(article => {
const title = article.dataset.title || '';
const tags = article.dataset.tags || '';
const category = article.dataset.category || '';
const matches = [title, tags, category].some(field =>
field.toLowerCase().includes(normalizedTerm)
);
article.style.display = matches ? '' : 'none';
});
}
Dark Mode com Persistência
// Theme toggle com sistema de preferência
class ThemeManager {
constructor() {
this.theme = this.getStoredTheme() || this.getPreferredTheme();
this.applyTheme(this.theme);
}
getStoredTheme() {
return localStorage.getItem('theme');
}
getPreferredTheme() {
return window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark' : 'light';
}
toggle() {
this.theme = this.theme === 'dark' ? 'light' : 'dark';
this.applyTheme(this.theme);
localStorage.setItem('theme', this.theme);
}
}
SEO e Performance
---
// BaseLayout.astro - Meta tags otimizadas
const { title, description, image } = Astro.props;
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
---
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- SEO Essentials -->
<title>{title}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonicalURL} />
<!-- Open Graph -->
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={image} />
<!-- Performance hints -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="dns-prefetch" href="//fonts.gstatic.com">
</head>
O Papel da IA no Desenvolvimento
Autocomplete Inteligente
Utilizei muito o GitHub Copilot e Cursor AI para:
// Exemplo de código gerado com assistência de IA
export function generateReadingTime(content: string): string {
// IA sugeriu automaticamente esta implementação otimizada
const wordsPerMinute = 200;
const wordCount = content
.replace(/[^\w\s]/g, '')
.split(/\s+/)
.filter(word => word.length > 0).length;
const minutes = Math.ceil(wordCount / wordsPerMinute);
return `${minutes} min`;
}
Testes Automatizados
A IA me ajudou a escrever testes abrangentes:
// Testes gerados com assistência de IA
describe('Search Functionality', () => {
beforeEach(() => {
// Setup DOM elements
document.body.innerHTML = `
<input id="search" type="text" />
<div data-searchable data-title="typescript guide"></div>
`;
});
test('should filter articles based on search term', () => {
const searchInput = document.getElementById('search');
const article = document.querySelector('[data-searchable]');
// Simulate search
searchInput.value = 'typescript';
searchInput.dispatchEvent(new Event('input'));
expect(article.style.display).not.toBe('none');
});
});
Otimizações de Performance
A IA sugeriu várias otimizações:
// Lazy loading de imagens
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy');
imageObserver.unobserve(img);
}
});
});
// Debounce para eventos frequentes
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
Processo de Design e UX
Design System Coeso
Criei um sistema de design baseado em:
/* Design tokens */
:root {
--color-primary-50: #eff6ff;
--color-primary-600: #2563eb;
--space-xs: 0.25rem;
--space-sm: 0.5rem;
--space-md: 1rem;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--border-radius: 0.5rem;
}
/* Componente base */
.btn {
@apply px-4 py-2 rounded-lg font-medium transition-all duration-200;
@apply focus:outline-none focus:ring-2 focus:ring-offset-2;
}
.btn-primary {
@apply bg-indigo-600 text-white hover:bg-indigo-700;
@apply focus:ring-indigo-500;
}
Micro-interações
Implementei animações sutis para melhorar UX:
/* Hover effects suaves */
.card {
@apply transition-all duration-300;
@apply hover:shadow-xl hover:-translate-y-1;
}
/* Loading states */
.skeleton {
@apply animate-pulse bg-gray-200 dark:bg-gray-700;
}
/* Focus states acessíveis */
.focus-ring {
@apply focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2;
@apply dark:focus:ring-offset-gray-900;
}
Challenges e Soluções
Performance de Build
Problema: Build times crescendo com mais conteúdo
Solução: Implementei build incremental e lazy loading:
// astro.config.mjs
export default defineConfig({
experimental: {
contentCollectionCache: true
},
vite: {
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
utils: ['lodash', 'date-fns']
}
}
}
}
}
});
SEO para SPA-like Navigation
Problema: Manter SEO com interações dinâmicas
Solução: Hidratação seletiva com Astro Islands:
---
// Apenas componentes interativos são hidratados
---
<SearchBar client:load />
<StaticContent />
<FilterButtons client:idle />
Métricas e Resultados
Performance Metrics
Após otimizações, consegui:
- Lighthouse Score: 98/100
- First Contentful Paint: < 1.2s
- Largest Contentful Paint: < 2.5s
- Cumulative Layout Shift: < 0.1
- Bundle Size: ~45KB (gzipped)
Developer Experience
- Build Time: ~3s para builds incrementais
- Hot Reload: < 500ms
- Type Safety: 100% TypeScript coverage
- Code Quality: ESLint + Prettier configurados
Lições Aprendidas
Tecnológicas
- Astro é excelente para content-heavy sites: Zero JS por padrão resulta em performance superior
- Tailwind + TypeScript: Combinação poderosa para DX e maintainability
- AI-assisted development: Aumenta significativamente a velocidade de desenvolvimento
Processo
- Start simple, iterate fast: Comecei com MVP e adicionei features incrementalmente
- Design system first: Investir tempo em tokens e componentes base acelera desenvolvimento posterior
- Performance budget: Definir limites de performance desde o início previne regressões
Próximos Passos
Features Planejadas
- Analytics privacy-focused: Implementar tracking sem cookies
- Newsletter integration: Sistema de assinatura para updates
- Comment system: Usando GitHub Discussions API
- PWA capabilities: Service worker para offline reading
Otimizações Técnicas
- Edge deployment: Migrar para Vercel Edge Functions
- Image optimization: Implementar responsive images com diferentes formatos
- Internationalization: Suporte a múltiplos idiomas
Conclusão
Este projeto foi muito além de um simples blog. Tornou-se um laboratório para experimentar tecnologias modernas, praticar boas práticas de desenvolvimento e documentar minha jornada profissional.
A combinação de Astro + Tailwind + TypeScript provou ser extremamente produtiva, especialmente com o auxílio de ferramentas de IA para acelerar o desenvolvimento e garantir qualidade do código.
Principais takeaways:
- Performance importa: Users percebem a diferença
- Developer Experience: Ferramentas certas fazem toda diferença
- AI as a pair programmer: Aumenta velocidade sem comprometer qualidade
- Iterative development: Melhor que big bang releases
O código completo está disponível no GitHub, e continuo documentando novas funcionalidades e otimizações conforme implemento.
Este artigo foi escrito enquanto continuo desenvolvendo e melhorando o blog. Se você tem sugestões ou quer discutir algum aspecto técnico, fique à vontade para entrar em contato!