Ingeniería 9 min de lectura

Implementación completa del sistema de blogs en Astro 4.8 - Un enfoque integral con traducción automática por IA y pruebas E2E

Registro de la implementación de un sistema de blogs de alto rendimiento basado en Astro Content Collections. Se detalla el proceso de desarrollo integral, que incluye traducción automática por IA con la API Google Gemini, pruebas E2E con Playwright y funcionalidad de limitación de velocidad.

Terisuke
Share this article:

Resumen

En el desarrollo reciente, hemos implementado un sistema de blog integral basado en Astro 4.8.7. Esta plataforma de blog tecnológico moderna no solo muestra contenido en formato Markdown, sino que también incluye funciones como traducción automática con IA, pruebas E2E (End-to-End) y un conjunto de funcionalidades preparadas para un uso en producción.

Se acabó la época de pelearse con los widgets de WordPress. Ahora, puedes dejar que la IA se encargue de las traducciones, automatizar las pruebas y los ingenieros podrán dormir tranquilos (es broma).

Stack Tecnológico

Tecnologías Principales

  • Astro 4.8.7: SSG (Static Site Generator) de alta velocidad con arquitectura de islas.
  • TypeScript: Entorno de desarrollo seguro por tipos.
  • Tailwind CSS: Estilizado basado en la utilidad (utility-first).
  • Alpine.js 3.14.0: JavaScript ligero para front-end.

Funcionalidades Específicas del Blog

  • Content Collections: Gestión de contenido seguro por tipos en Astro.
  • Google Gemini API: Motor de traducción automática con IA.
  • Playwright: Automatización de pruebas E2E.
  • remark-link-card-plus: Generación de tarjetas de enlace enriquecidas.

Arquitectura Central de Implementación

1. Diseño de Content Collections

Hemos adoptado Content Collections de Astro, alejándonos de la gestión tradicional de archivos Markdown. Ya no tendrás que preguntarte: “¿Estaba escribiendo el frontmatter de esta manera correcta?”.

// 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),
  }),
});

Ventajas:

  • Prevención de errores de metadatos mediante validación de tipos en tiempo de compilación.
  • Actualización en tiempo real con Hot Reloading.
  • Validación automática del esquema.

2. Diseño del Sistema de Traducción con IA

Hemos construido un sistema de traducción automática utilizando la API de Google Gemini. Lo que tardaría días con traductores humanos, la IA lo hace en segundos. Y encima, 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 = `Traduce la siguiente entrada de blog en japonés a inglés. 
  Traduce los términos técnicos apropiadamente y haz que sea inglés legible:

${japaneseContent}`;

  const result = await model.generateContent(prompt);
  return result.response.text().trim();
}

Características:

  • Limitación de Tasa (Rate Limiting): Un límite conservador de 15 peticiones por minuto.
  • Manejo de Errores: Reintentos con retroceso exponencial (exponential backoff).
  • Seguridad YAML: Escapado adecuado del frontmatter.

3. Sistema de Limitación de Tasa

Hemos implementado una función de limitación de tasa para garantizar la estabilidad de las operaciones de la API. Para evitar que Google nos diga: “¡Estás enviando demasiadas peticiones!“.

// 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

Hemos implementado pruebas exhaustivas de las funcionalidades del blog utilizando Playwright. No basta con decir “está funcionando bien”.

// e2e/blog.spec.ts
test.describe('Funcionalidad del Blog', () => {
  test('debería navegar al blog en japonés', async ({ page }) => {
    await page.goto('/blog/');
    await expect(page.locator('h1')).toContainText('技術ブログ'); // Blog Técnico
  });

  test('debería mostrar la imagen OGP para las entradas del blog', 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 de 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

  • Entrega de imágenes en formato AVIF.
  • Fallback a WebP.
  • Tamaños de imagen responsivos (480w, 800w).

Desafíos y Soluciones

1. Problema de Escapado en YAML Frontmatter

Desafío: Errores de análisis de YAML cuando los títulos o descripciones traducidas contienen caracteres especiales.

Solución:

function escapeYAMLString(str) {
  return str
    .replace(/\\/g, "\\\\") // Escapa primero las barras invertidas
    .replace(/"/g, '\\"');   // Escapa las comillas dobles
}

2. Manejo de la Limitación de Tasa de la API

Desafío: Fallos en las peticiones debido a las limitaciones de la API de Gemini.

Solución: Retroceso exponencial y limitación de tasa inteligente.

  • Retraso basado en segundos.
  • Retraso gradual hasta un máximo de 60 segundos.
  • Limitación proactiva rastreando los tiempos de las peticiones.

3. Estabilidad de las Pruebas E2E

Desafío: Inestabilidad de las pruebas debido a contenido dinámico.

Solución: Identificación fiable de elementos utilizando el atributo data-testid.

Flujo de Operación

Proceso de Publicación de Nuevos Artículos

  1. Creación de Artículo en Japonés: Crear archivo Markdown en /src/content/blog/ja/.
  2. Traducción con IA: Ejecutar npm run translate src/content/blog/ja/nombre-del-articulo.md.
  3. Ejecución de Pruebas: Ejecutar npm run test:e2e.
  4. Compilación: Ejecutar npm run build.
  5. Despliegue: Despliegue automático en Firebase Hosting.

Garantía de Calidad

  • Comprobación de Tipos: Verificación en tiempo de compilación con TypeScript.
  • Validación de Esquema: Verificación de contenido con Zod.
  • Pruebas E2E: Pruebas funcionales con Playwright.

Lecciones Aprendidas

1. El Poder de Content Collections

En comparación con la gestión tradicional basada en archivos, la seguridad por tipos y la experiencia de desarrollo han mejorado drásticamente. En particular, la posibilidad de refactorizar de forma segura al tener claro el alcance de los cambios en el esquema.

Ahora TypeScript nos avisa con “¡el tipo es incorrecto!”, por lo que ya no nos asustamos con errores en tiempo de ejecución. Es genial.

2. La Practicidad de la Traducción con IA

La calidad de las traducciones de la API de Google Gemini es muy alta para artículos técnicos, lo que ha minimizado la necesidad de ajustes manuales. Sin embargo, la coherencia de los términos técnicos requiere una mejora continua.

Me hizo gracia cuando “npm” se tradujo como “en-pi-em”. Bueno, no está del todo mal.

3. La Importancia de las Pruebas E2E

Hemos comprobado que, incluso con generadores de sitios estáticos, las pruebas E2E son esenciales para funciones complejas como el enrutamiento y la generación de metadatos.

Me daría ganas de golpear a mi yo del pasado que pensaba: “Los sitios estáticos no necesitan pruebas, ¿verdad?”.

Resultados de Rendimiento

  • First Contentful Paint (FCP): 0.8 segundos.
  • Largest Contentful Paint (LCP): 1.2 segundos.
  • Cumulative Layout Shift (CLS): 0.05.
  • Tamaño total del bundle: 45 KB (después de compresión gzip).

Conclusión

A través de la implementación de este sistema de blog, hemos confirmado la importancia de la arquitectura JAMstack moderna en los siguientes aspectos:

  1. Seguridad por Tipos: Prevención de errores en tiempo de diseño gracias a Content Collections (no volveremos a llorar por errores en tiempo de ejecución).
  2. Automatización: Eficiencia operativa mejorada mediante traducción con IA y pruebas E2E (robando el trabajo de los humanos).
  3. Rendimiento: Alta velocidad gracias a la optimización proactiva (el culmen de la velocidad).
  4. Mantenibilidad: Desarrollo sostenible gracias a una arquitectura clara (amable con nuestro yo futuro).

Como plataforma de blog tecnológico, hemos logrado la automatización completa desde la redacción hasta la publicación de artículos, creando un entorno en el que los desarrolladores pueden centrarse en la creación de contenido esencial.

En otras palabras, ahora ya no tenemos excusas para no actualizar el blog. ¿Es eso maravilloso…?

Support this article

If this article was helpful, please support us with a tip. You can choose any amount.

Secure payment via Stripe

Artículos Relacionados

Leer artículo
韓国語ブログ404ページ
Ingeniería

【Soporte completo para 5 idiomas】Crónica de una batalla furiosa de 3 horas para expandir un blog que solo era para inglés y japonés a chino, coreano y español

El impactante hecho de que, aunque pensábamos que era compatible con 5 idiomas, en realidad solo tenía 2. El registro completo de la implementación ultrarrápida del soporte para chino, coreano y español con Claude Code.

#多言語化 #i18n +4
Leer artículo
Google Cloud Platform ロゴ
Ingeniería

La migración completa de un proyecto de Google Cloud entre organizaciones se completó en un día

Los registros de las lágrimas de un desarrollador que había creado un script para migrar GCS poco a poco, solo para descubrir que los proyectos se podían mover enteros.

#Google Cloud #DevOps +3
Leer artículo
高性能Webサイトのイメージ
Ingeniería

La historia de cómo intenté una y otra vez el sitio web de Hiroshi Abe y creé un sitio web increíble

La crónica y las ideas técnicas de desafiar continuamente el sitio web de Hiroshi Abe como "el hombre con el sitio web autoproclamado más rápido en descender".

#Astro #Alpine.js +3