Generación dinámica de PDF: ingeniería del papel digital
Cómo generar PDF de alta fidelidad (Facturas, Tickets) usando React y Node.js. Una comparación de @react-pdf/renderer vs Puppeteer en entornos sin servidor.
El mundo funciona con HTML, pero los negocios funcionan con PDF.
Un pedido de comercio electrónico no es “real” hasta que exista una Factura. Una entrada para un concierto no es “válida” hasta que haya un código QR en un PDF.
Durante años, generar archivos PDF fue la tarea más odiada en el desarrollo backend. Se trataba de herramientas arcaicas como wkhtmltopdf, plantillas XML o frágiles scripts de Python.
En Maison Code Paris, llevamos la generación de PDF a la era moderna. Utilizamos la misma arquitectura de componentes (React) para nuestros documentos que para nuestras interfaces de usuario. Esto garantiza que la Consistencia de la marca sea absoluta. La fuente del sitio web es la fuente de la factura.
Por qué Maison Code analiza esto
En Maison Code Paris, actuamos como la conciencia arquitectónica de nuestros clientes. A menudo heredamos pilas “modernas” que se construyeron sin una comprensión fundamental de la escala. Vemos API simples que tardan 4 segundos en responder debido a problemas de consultas N+1 y “microservicios” que cuestan €5000 al mes en tarifas de nube inactiva.
Discutimos este tema porque representa un punto crítico en la madurez de la ingeniería. Implementar esto correctamente diferencia un MVP frágil de una plataforma resistente de nivel empresarial que puede manejar el tráfico del Black Friday sin sudar.
El paisaje: cómo renderizar un PDF
Hoy en día, existen tres formas principales de generar un PDF, cada una con enormes ventajas y desventajas.
| Enfoque | Herramientas | Ventajas | Contras |
|---|---|---|---|
| Sin navegador (Chrome sin cabeza) | Titiritero, Dramaturgo | Compatibilidad con CSS con píxeles perfectos. Si puede compilarlo en HTML, puede imprimirlo. | Lento. Uso intensivo de memoria. Requiere iniciar una instancia del navegador (Chromium), lo cual es complicado en Serverless. |
| Primitivas de PDF | PDFKit, jsPDF | Extremadamente rápido. Cero dependencias. | Desarrollador H*. Tienes que dibujar líneas manualmente (doc.moveTo(100, 100).lineTo(200, 200)). Mantener diseños es una pesadilla. |
| Reaccionar-PDF / @react-pdf/renderer | Reaccionar, Flexbox | El Santo Grial. Escriba componentes de React, obtenga un PDF. Lo suficientemente rápido. | Solo subconjunto CSS (principalmente Flexbox). Aún no hay soporte para Grid. |
En Maison Code, estandarizamos estrictamente React-PDF.
La arquitectura: por qué gana React-PDF
El cambio de modelo mental es simple: Un PDF es solo otro objetivo de renderizado.
Al igual que ReactDOM se representa en DOM y ReactNative se representa en vistas de iOS/Android, @react-pdf/renderer se representa en la especificación PDF.
1. Código compartido
Puede compartir sus tipos de tokens de Design System.
importar {Hoja de estilo} desde '@react-pdf/renderer';
importar {tema} desde '@/design-system/theme';
estilos constantes = Hoja de estilo.create({
encabezado: {
fontFamily: theme.fonts.heading, // "Bodoni Moda"
color: tema.colores.void, // #000000
tamaño de fuente: 24,
}
});
Esto garantiza que su factura coincida píxel por píxel con su página de pago.
2. Arranques en frío sin servidor
Ejecutar Puppeteer en AWS Lambda es una batalla constante contra el límite del paquete de 50 MB y los arranques en frío de 10 segundos. React-PDF es solo una biblioteca de Node.js. Efectivamente agrega 0 ms a su arranque en frío. Compila cadenas en buffers binarios. Está vinculado a la CPU, no a las E/S.
Implementación: el componente “Papel digital”
A continuación se muestra un ejemplo del mundo real de un componente de factura.
importar {Documento, Página, Texto, Vista, Hoja de estilo, Fuente} desde '@react-pdf/renderer';
// Registrar fuentes personalizadas (crítico para la marca)
Registro de fuente ({
familia: 'Bodoni Moda',
src: 'https://cdn.maisoncode.paris/fonts/BodoniModa-Regular.ttf'
});
const Factura = ({ pedido }) => (
<Documento>
<Tamaño de página="A4" estilo={styles.page}>
{/* Encabezado */}
<Ver estilo={styles.header}>
<Text style={styles.brand}>CÓDIGO DE CASA.</Text>
<Text estilo={styles.invoiceId}>INV-{order.id}</Text>
</Ver>
{/* Líneas de pedido */}
<Ver estilo={styles.table}>
{order.items.map(item => (
<Ver estilo={styles.row}>
<Estilo de texto={styles.cellDesc}>{item.name}</Text>
<Estilo de texto={styles.cellQty}>x{item.quantity}</Text>
<Estilo de texto={styles.cellTotal}>€{item.price}</Text>
</Ver>
))}
</Ver>
{/* Pie de página */}
<Ver estilo={styles.footer}>
<Texto>Gracias por su negocio. Este documento es un original digital.</Text>
</Ver>
</Página>
</Documento>
);
El punto final API
No guarda archivos en el disco. Los transmite directamente al cliente o al S3.
// Ruta API Next.js / Node.js
importar {renderToStream} desde '@react-pdf/renderer';
exportar función asíncrona POST(req) {
const stream = await renderToStream(<Pedido de factura={req.body} />);
devolver nueva respuesta (flujo, {
encabezados: {
'Tipo de contenido': 'aplicación/pdf',
'Disposición-Contenido': 'adjunto; nombre de archivo="factura.pdf"'
}
});
}
Rendimiento: la regla de los 500 ms
En el comercio electrónico, si el botón “Descargar factura” gira durante 5 segundos, el usuario asume que el sitio no funciona. Puppeteer tarda entre 3 y 8 segundos en iniciarse, navegar e imprimir. React-PDF tarda 200 ms-600 ms en generar una factura compleja.
Esta diferencia de velocidad le permite generar archivos PDF sincrónicamente bajo demanda, en lugar de ponerlos en cola en un trabajo en segundo plano (Celery/SQS) y enviarlos por correo electrónico más tarde. Una parte móvil menos. Una cola menos que vigilar.
Conclusión
Dejemos de tratar a los archivos PDF como ciudadanos de segunda clase. Al adoptar React-PDF, incorpora la capa de documento a su flujo de trabajo de ingeniería estándar.
- Control de versiones: sus plantillas de factura tienen seguimiento de git.
- Seguridad de tipos: la generación de su PDF falla en el momento de la compilación si omite un campo “precio”.
- Consistencia en el diseño: su marca sigue siendo premium, incluso en papel.
En el sector del lujo, la experiencia post-compra es tan importante como la venta. Una factura hermosa e instantánea es el toque final de una transacción premium.
Contrate a nuestros arquitectos para auditar su proceso de generación de documentos.