Implementación completa de un sistema de blog en Astro 4.8: un enfoque integral que incluye traducción por IA y pruebas E2E
Registro de implementación de un sistema de blog de alto rendimiento basado en Astro Content Collections. Se explica el proceso de desarrollo integral, incluida la traducción automática por IA con la API de Google Gemini, pruebas E2E con Playwright y funciones de limitación de tasa.
Resumen
En un desarrollo reciente, implementamos un sistema de blog integral basado en Astro 4.8.7. No se trata solo de un sistema para mostrar Markdown, sino de una moderna plataforma de blog técnico equipada con traducción automática mediante IA, pruebas E2E y funciones diseñadas para una operación a gran escala.
La era de pelear con widgets en WordPress ha terminado. A partir de ahora, dejamos que la IA traduzca, automatizamos las pruebas y los ingenieros podemos simplemente dormir (es broma).
Stack tecnológico
Tecnologías centrales
- Astro 4.8.7: SSG de alta velocidad mediante arquitectura en islas (Islands Architecture)
- TypeScript: entorno de desarrollo con tipado seguro
- Tailwind CSS: estilizado utility-first
- Alpine.js 3.14.0: JavaScript ligero para frontend
Funciones dedicadas al blog
- Content Collections: gestión de contenidos con tipado seguro de Astro
- API de Google Gemini: motor de traducción automática con IA
- Playwright: automatización de pruebas E2E
- remark-link-card-plus: generación de link cards enriquecidas
Arquitectura central de la implementación
1. Diseño de Content Collections
Pasamos de la gestión tradicional de archivos Markdown al Content Collections de Astro. Ya no hay que preocuparse pensando: “¿Habré escrito bien este frontmatter?”.
// src/content/config.ts
const blogCollection = defineCollection({
type: 'content',
schema: z.object({
title: z.string(),
description: z.string(),
pubDate: z.coerce.date(),
category: z.enum(['ai', 'engineering', 'founder', 'lab']),
tags: z.array(z.string()).default([]),
lang: z.enum(['ja', 'en']).default('ja'),
featured: z.boolean().default(false),
}),
});
Las ventajas son las siguientes:
- Prevención de errores de metadatos mediante la verificación de tipos en tiempo de compilación
- Actualizaciones en tiempo real con Hot Reloading
- Validación automática de esquemas
2. Diseño del sistema de traducción con IA
Creamos un sistema de traducción automática utilizando la API de Google Gemini. Termina mucho más rápido que encargárselo a traductores humanos. Y, además, no se queja.
// scripts/translate-blog.js
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY);
const model = genAI.getGenerativeModel({
model: "gemini-2.5-flash-lite-preview-06-17"
});
async function translateBlogPost(japaneseContent) {
const prompt = `Translate the following Japanese blog post to English.
Translate technical terms appropriately and make it readable English:
${japaneseContent}`;
const result = await model.generateContent(prompt);
return result.response.text().trim();
}
Las características son las siguientes:
- Límite de tasa (Rate Limiting): límite conservador de 15 solicitudes/minuto
- Manejo de errores: función de reintento mediante retroceso exponencial (exponential backoff)
- Seguridad en YAML: procesamiento adecuado de escape para el frontmatter
3. Sistema de límite de tasa (Rate Limiting)
Para operar la API de forma estable, implementamos una función de límite de tasa. También sirve para que Google no se enfade diciendo: “¡Estás enviando demasiadas solicitudes!“.
// scripts/rate-limiter.js
class RateLimiter {
constructor({ requestsPerMinute = 15, maxRetries = 3 }) {
this.requestsPerMinute = requestsPerMinute;
this.maxRetries = maxRetries;
this.requestTimes = [];
}
async executeWithRetry(operation, description) {
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
try {
await this.checkRateLimit();
return await operation();
} catch (error) {
if (attempt === this.maxRetries) throw error;
await this.backoff(attempt);
}
}
}
}
4. Implementación de pruebas E2E
Utilizando Playwright, implementamos pruebas integrales para las funciones del blog. La actitud de “¡funciona, así que todo bien!” no basta.
// e2e/blog.spec.ts
test.describe('Blog functionality', () => {
test('should navigate to Japanese blog', async ({ page }) => {
await page.goto('/blog/');
await expect(page.locator('h1')).toContainText('技術ブログ');
});
test('should display OGP image for blog posts', async ({ page }) => {
await page.goto('/blog/');
const firstPost = page.locator('[data-testid="blog-post"]').first();
await firstPost.click();
const ogImage = page.locator('meta[property="og:image"]');
await expect(ogImage).toHaveAttribute('content', /\/og\/.*\.svg/);
});
});
Optimización del rendimiento
Configuración de compresión y optimización
// astro.config.mjs
integrations: [
compress({
CSS: true,
HTML: {
'remove-comments': true,
'minify-js': true,
'minify-css': true
},
JavaScript: true,
SVG: true
}),
compressor({
gzip: true,
brotli: true
})
]
Optimización de imágenes
- Distribución de imágenes en formato AVIF
- Fallback a WebP
- Tamaños de imagen responsivos (480w, 800w)
Desafíos y soluciones
1. Problema de escape en YAML Frontmatter
El desafío residía en que, si los títulos o descripciones traducidos contenían caracteres especiales, se producía un error de análisis sintáctico (parse error) en YAML.
Como solución, se escapan con la siguiente función:
function escapeYAMLString(str) {
return str
.replace(/\\/g, "\\\\") // バックスラッシュを最初にエスケープ
.replace(/"/g, '\\"'); // ダブルクォートをエスケープ
}
2. Respuesta a los límites de tasa de la API
El desafío era que las solicitudes fallaban debido a los límites de la API de Gemini.
La solución fue el retroceso exponencial y un límite de tasa inteligente:
- Retardo base de 1 segundo
- Retardo progresivo de hasta 60 segundos
- Limitación preventiva mediante el seguimiento del registro temporal de solicitudes
3. Estabilidad de las pruebas E2E
El desafío consistía en que el contenido dinámico provocaba inestabilidad en las pruebas (flakiness).
La solución fue identificar los elementos de forma certera utilizando el atributo data-testid.
Flujo de operaciones
Proceso de publicación de un nuevo artículo
- Creación del artículo en japonés: crear el archivo Markdown en
/src/content/blog/ja/ - Traducción con IA:
npm run translate src/content/blog/ja/article-name.md - Ejecución de pruebas:
npm run test:e2e - Compilación (build):
npm run build - Despliegue: despliegue automático a Firebase Hosting
Aseguramiento de la calidad
- Comprobación de tipos: verificación en tiempo de compilación mediante TypeScript
- Validación de esquemas: verificación de contenidos mediante Zod
- Pruebas E2E: pruebas funcionales mediante Playwright
Lecciones aprendidas
1. El poder de Content Collections
En comparación con la gestión tradicional basada en archivos, la seguridad de tipos y la experiencia de desarrollo mejoraron drásticamente. En particular, como el alcance del impacto al cambiar un esquema quedó claramente definido, ahora es posible refactorizar con total seguridad.
Ahora TypeScript nos regaña con un “¡el tipo no coincide!”, por lo que ya no tenemos que asustarnos por errores en tiempo de ejecución. Es fantástico.
2. Utilidad práctica de la traducción con IA
La calidad de traducción de la API de Google Gemini en artículos técnicos fue sumamente alta, y los retoques manuales fueron mínimos. No obstante, se requiere una mejora continua en la coherencia de la terminología técnica.
Me dio risa cuando tradujo “npm” como “エヌピーエム” (enuepiemu). Bueno, equivocado no estaba.
3. La importancia de las pruebas E2E
Comprobé que, incluso en un generador de sitios estáticos, las pruebas E2E son indispensables para funciones complejas como el enrutamiento o la generación de metadatos.
Me gustaría darle un golpe a mi yo del pasado, que pensaba: “Como es un sitio estático, no necesita pruebas, ¿verdad?”.
Conclusión
A través de la implementación de este sistema de blog, pudimos confirmar que los siguientes puntos son fundamentales en una arquitectura JAMstack moderna:
- Seguridad de tipos: prevención de errores en tiempo de diseño gracias a Content Collections (se acabaron las lágrimas por errores en tiempo de ejecución)
- Automatización: eficiencia operativa mediante traducción con IA y pruebas E2E (arrebatándole el trabajo a los humanos)
- Rendimiento: mayor velocidad gracias a optimizaciones proactivas (la cúspide de la velocidad extrema)
- Mantenibilidad: desarrollo sostenible gracias a una arquitectura clara (amable con nuestro yo del futuro)
Como plataforma de blog técnico, automatizamos el flujo que va desde la redacción del artículo hasta su publicación, creando un entorno en el que los desarrolladores pueden concentrarse en crear el contenido de los artículos.
En otras palabras, esto significa que nos hemos quedado sin excusas para no actualizar el blog. Es maravilloso… ¿o no?
¿Quiere aplicar esto en su empresa?
Nuestra recepción con IA «Cloudia» atiende solicitudes de desarrollo de IA por encargo.
Más información: Plataforma de IA y desarrollo por contratoSupport this article
If this article was helpful, please support us with a tip. You can choose any amount.
Artículos Relacionados
Qué se ve y qué no se ve en el historial de Git: comprobamos cuatro OSS con Grift
Separamos qué se puede contar en un historial de git con reglas explícitas y qué no. Comprobamos cuatro OSS reales por repositorio. No garantiza la capacidad de una persona ni que el registro esté completo.
Cómo mantener en la implementación el principio de «no asignar puntuaciones ni clasificaciones»: las 5 condiciones que Grift CLI ha establecido para la próxima versión
Grift CLI promete no emitir puntuaciones ni clasificaciones. En la verificación cruzada de octubre de 2026, se descubrió que, si bien una nota indicaba que no se trataba de una clasificación, la tabla estaba ordenada de forma descendente por número de commits. Explicamos de forma sencilla las 5 condiciones de aceptación impuestas para la versión 0.8, dirigidas a clientes, comerciales de SES e ingenieros.
Por qué las estimaciones en desarrollo de IA y por encargo dependen de cada persona: cómo convertir los fundamentos en activos de la empresa
Explicamos por qué las estimaciones en el desarrollo por encargo varían según la persona y cómo crear fundamentos explicables utilizando el historial de GitHub, los precios de mercado y el desglose de horas de trabajo. También presentamos el enfoque para utilizar Grift.