Generación de PDFs en Astro con Cloudflare… | LaunchFast
LaunchFast Logo LaunchFast
Blog
1929 palabras 10 min de lectura

Generación de PDFs en Astro con Cloudflare Browser Rendering en el edge

Aprenda cómo generar facturas, informes e imágenes OG como PDFs directamente desde sus páginas Astro usando Cloudflare Browser Rendering. Ejecute Chromium headless en el edge, aplique CSS de impresión y transmita PDFs con latencia mínima.

Rishi Raj Jain
Rishi Raj Jain Autor
Generación de PDFs en Astro con Cloudflare Browser Rendering en el edge

Generar PDFs del lado del servidor suele implicar lidiar con cold starts de Lambda, gestionar binarios de Chromium o depender de APIs de terceros que añaden latencia y costos. Si alguna vez ha levantado un contenedor Docker de más de 1 GB solo para convertir HTML a PDF, conoce el problema.

Sponsored

Kits de inicio de alta calidad con flujo de autenticación integrada (Auth.js), carga de objetos (AWS, Clouflare R2, Firebase Storage, Supabase Storage), pagos integrados (Stripe, LemonSqueezy), flujo de verificación de correo electrónico (Resend, Postmark, Sendgrid) y mucho más . Compatible con cualquier base de datos (Redis, Postgres, MongoDB, SQLite, Firestore).

Get all 3 kits Bundle ↗

One-time license · Lifetime updates

Cloudflare Browser Rendering invierte este modelo. Es un servicio gestionado de Chromium headless que se ejecuta en la red edge de Cloudflare, es decir, sin binarios que empaquetar, sin cold starts y sin capas de Docker. Obtiene APIs compatibles con Puppeteer que se ejecutan de forma globalmente distribuida con tiempos de arranque inferiores a 100 ms.

En esta guía, construirá un sistema de generación de PDFs listo para producción usando Astro, Cloudflare KV y Cloudflare Workers. Creará páginas de recibos imprimibles con CSS personalizado, conectará un endpoint de API que lanza Chrome headless en el edge y almacenará en caché los resultados en Cloudflare KV para evitar renderizados redundantes.

Requisitos previos

Necesitará lo siguiente:

¿Por qué Cloudflare Browser Rendering para PDFs?

  • Sin gestionar Chromium: Cloudflare ejecuta y mantiene actualizado Chromium headless por usted.
  • Proximidad en el edge: Renderice PDFs cerca del solicitante; ideal para paneles, facturas e imágenes OG.
  • Streaming: Envíe PDFs directamente desde el worker sin archivos temporales.
  • Consciente de costos: Pague por uso sin mantener una flota de renderizadores.

Descripción general de la arquitectura

1. Página Astro (src/pages/receipt/[id].astro)
→ Ruta SSR que renderiza su HTML de recibo/factura + CSS de impresión
2. API de PDF (src/pages/api/pdf/[id].ts)
→ Crea una sesión de Browser Rendering
→ Carga la URL de la ruta Astro
→ Llama a page.pdf() y transmite el binario
3. Adaptador de Cloudflare + binding de Browser
→ Despliega Astro en Workers/Pages
→ Proporciona un binding BROWSER al worker

Crear una nueva aplicación Astro

Comencemos creando un nuevo proyecto Astro. Ejecute el siguiente comando:

Terminal window
npm create astro@latest my-astro-kv-pdf-app
cd my-astro-kv-pdf-app
npm install wrangler @cloudflare/puppeteer

Cuando se le solicite, elija:

  • Use minimal (empty) template cuando se le pregunte cómo iniciar el nuevo proyecto.
  • Yes cuando se le pregunte si desea instalar dependencias.
  • Yes cuando se le pregunte si desea inicializar un repositorio git.

Una vez hecho esto, puede moverse al directorio del proyecto e iniciar la aplicación:

Terminal window
npm run dev

La aplicación debería estar ejecutándose en localhost:4321.

Integrar el adaptador de Cloudflare en su proyecto Astro

Para desplegar su proyecto Astro en Cloudflare Workers y usar Cloudflare KV, necesita instalar el adaptador de Cloudflare. Ejecute el comando siguiente:

Terminal window
npx astro add cloudflare --yes

Actualice astro.config.mjs para que output sea server:

astro.config.mjs
import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';
export default defineConfig({
output: 'server',
adapter: cloudflare()
});

Configurar Browser Rendering en wrangler.jsonc

Añada un binding BROWSER para que el worker pueda lanzar Chromium headless:

wrangler.jsonc
{
"main": "dist/_worker.js/index.js",
"name": "my-astro-kv-pdf-app",
"compatibility_date": "2025-12-06",
"compatibility_flags": [
"nodejs_compat",
"global_fetch_strictly_public"
],
"assets": {
"binding": "ASSETS",
"directory": "./dist"
},
"observability": {
"enabled": true
},
"browser": {
"binding": "BROWSER"
}
}

El bloque browser provisiona el servicio Browser Rendering de Cloudflare y lo expone a su worker como env.BROWSER.

Añadir KV para caché

Cree un namespace KV para almacenar en caché los PDFs generados:

Terminal window
npx wrangler kv namespace create PDF_CACHE

Esto mostrará un id que añadirá a wrangler.jsonc. Actualice el archivo para incluir el binding KV:

wrangler.jsonc
{
"main": "dist/_worker.js/index.js",
"name": "my-astro-kv-pdf-app",
"compatibility_date": "2025-12-06",
"compatibility_flags": [
"nodejs_compat",
"global_fetch_strictly_public"
],
"assets": {
"binding": "ASSETS",
"directory": "./dist"
},
"observability": {
"enabled": true
},
"browser": {
"binding": "BROWSER"
},
"kv_namespaces": [
{
"binding": "PDF_CACHE",
"id": "generated-id",
"remote": true
}
]
}

Añadir tipos de TypeScript

Cree src/env.d.ts para añadir los tipos adecuados para los bindings de Cloudflare:

src/env.d.ts
/// <reference types="astro/client" />
type KVNamespace = import('@cloudflare/workers-types').KVNamespace
type ENV = {
PDF_CACHE: KVNamespace
BROWSER: Fetcher
}
type Runtime = import('@astrojs/cloudflare').Runtime<ENV>
declare namespace App {
interface Locals extends Runtime {}
}

Esto le proporciona seguridad de tipos completa al acceder a locals.runtime.env.PDF_CACHE y locals.runtime.env.BROWSER en sus rutas.

Construir una página Astro imprimible

Cree una página de recibo con estilos aptos para impresión:

---
const { id } = Astro.params;
const order = {
id,
customer: 'Ada Lovelace',
total: '$128.00',
items: [
{ name: 'Edge Functions', price: '$50.00' },
{ name: 'PDF Rendering', price: '$78.00' }
]
};
---
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Receipt #{order.id}</title>
<style>
:root { font-family: 'Inter', system-ui, -apple-system, sans-serif; }
body { margin: 0; padding: 32px; color: #0f172a; }
header { display: flex; align-items: center; justify-content: space-between; }
table { width: 100%; border-collapse: collapse; margin-top: 24px; }
th, td { padding: 12px 8px; text-align: left; border-bottom: 1px solid #e2e8f0; }
.total { text-align: right; font-size: 1.125rem; font-weight: 700; }
@page { margin: 24mm; }
@media print {
body { background: white; }
a[href]::after { content: ''; }
}
</style>
</head>
<body>
<header>
<div>
<h1>Receipt #{order.id}</h1>
<p>Issued to {order.customer}</p>
</div>
<strong>launchfa.st</strong>
</header>
<table>
<thead>
<tr><th>Item</th><th>Price</th></tr>
</thead>
<tbody>
{order.items.map(item => (
<tr>
<td>{item.name}</td>
<td>{item.price}</td>
</tr>
))}
</tbody>
</table>
<p class="total">Total: {order.total}</p>
</body>
</html>

Guárdela como src/pages/receipt/[id].astro. El CSS de impresión (@page) establece los márgenes, y las reglas @media print eliminan las decoraciones de enlaces innecesarias.

Crear la ruta de API de PDF

Así es como crear una ruta de API al estilo Worker que usa el browser rendering de Cloudflare para generar y almacenar en caché una versión PDF de su página HTML de recibo Astro.

Configuraremos un endpoint de API (src/pages/api/pdf/[id].ts) que:

  • comprueba si un PDF ya está en caché en Cloudflare KV y lo devuelve de inmediato si está disponible
  • lanza un navegador headless mediante la API de Cloudflare Browser Rendering si no está en caché
  • navega a la página imprimible y genera un PDF
  • almacena el PDF resultante en KV durante 7 días para solicitudes futuras
src/pages/api/pdf/[id].ts
import type { APIRoute } from "astro";
import puppeteer from "@cloudflare/puppeteer";
// Helper to create a proper PDF HTTP response
const pdfResponse = (pdf: Buffer<ArrayBuffer>, id: string) => {
return new Response(pdf, {
headers: {
'Content-Type': 'application/pdf',
'CDN-Cache-Control': 'max-age=604800',
'Content-Disposition': `inline; filename="receipt-${id}.pdf"`
}
});
}
export const GET: APIRoute = async ({ locals, params, request }) => {
const id = params.id as string;
const origin = new URL(request.url).origin;
const targetUrl = `${origin}/receipt/${id}`;
const cache = locals.runtime.env.PDF_CACHE;
// Try KV cache first to avoid unnecessary browser work
const cachedPdf = await cache.get(targetUrl, "arrayBuffer");
if (cachedPdf)
return pdfResponse(Buffer.from(cachedPdf), id);
// Only run browser in Cloudflare's env
if (!locals.runtime.env.BROWSER)
return new Response('Browser binding not available locally', { status: 501 });
// Launch browser and render HTML to PDF
const session = await puppeteer.launch(locals.runtime.env.BROWSER);
const page = await session.newPage();
await page.goto(targetUrl, { waitUntil: 'networkidle0' });
const pdf = await page.pdf({
format: 'A4',
printBackground: true,
margin: { top: '24mm', right: '18mm', bottom: '24mm', left: '18mm' }
});
await session.close();
const result = Buffer.from(pdf);
// Cache for a week (604800 seconds)
await cache.put(targetUrl, result, { expirationTtl: 60 * 60 * 24 * 7 });
return pdfResponse(result, id);
};

Ahora, cuando acceda a /api/pdf/123, recibirá un PDF generado en vivo desde /receipt/123. Las solicitudes posteriores devuelven el PDF en caché hasta que expire.

Proteger y almacenar en caché sus PDFs

  • Autenticación: Exija un token de sesión o una cadena de consulta firmada antes de renderizar. Rechace las solicitudes no autenticadas de forma temprana.
  • Caché: Almacene en caché facturas estáticas durante periodos breves (Cache-Control: public, max-age=300) para evitar volver a renderizar. Para contenido dinámico, mantenga la caché privada.
  • Límites de tasa: Añada un limitador de tasa (KV) para endpoints de alto tráfico.

Desplegar en Cloudflare Workers

Despliegue su aplicación de generación de PDFs en producción:

Terminal window
# Build the project
npm run build
# Deploy to Cloudflare Workers
npx wrangler deploy

Tras el despliegue, su API estará disponible en https://your-worker.workers.dev/api/pdf/[id].

Conclusión

Cloudflare Browser Rendering transforma la generación de PDFs de una operación que consume muchos recursos en una función edge ligera. Al combinar las capacidades SSR de Astro con Chromium headless en el edge, puede generar facturas, recibos e informes bajo demanda sin gestionar infraestructura ni lidiar con cold starts.

Para casos de uso avanzados, explore documentos de varias páginas, encabezados y pies de página personalizados, o incluso la generación de capturas de pantalla para imágenes Open Graph. La API de Browser Rendering le ofrece control completo de Puppeteer, todo ejecutándose en el edge de Cloudflare.

Si tiene alguna pregunta o comentario, no dude en comunicarse conmigo en Twitter.

Sigue leyendo