mcpField
P
pdf-generation

pdf-generation

github.com/claude-dev-suite文档处理4674 次安装4 天前更新
代码仓库

关于 pdf-generation

涵盖 Node.js、React 和 Python 的 PDF 生成实践技能,介绍多种基于库的方法,并列出生产环境中的可靠性与资源管理注意事项。

主要功能

  1. 01使用 Puppeteer 将 HTML 转为 PDF
  2. 02使用 PDFKit 程序化生成 PDF
  3. 03通过 @react-pdf/renderer 将 React 组件转为 PDF
  4. 04使用 ReportLab 生成 Python PDF
  5. 05生产检查清单与反模式

适用场景

  1. 01将复杂 HTML 布局渲染为 PDF
  2. 02根据应用数据创建发票 PDF
  3. 03从 React 组件生成 PDF
  4. 04规划生产环境中的 PDF 生成

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/claude-dev-suite/claude-dev-suite --skill pdf-generation

安装后在 Claude Code 中输入/pdf-generation确认已加载。

详细介绍

PDF 生成

Puppeteer HTML 转 PDF(复杂布局时推荐)

import puppeteer from 'puppeteer';

async function generatePdf(html: string): Promise<Buffer> {
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();
  await page.setContent(html, { waitUntil: 'networkidle0' });

  const pdf = await page.pdf({
    format: 'A4',
    margin: { top: '20mm', bottom: '20mm', left: '15mm', right: '15mm' },
    printBackground: true,
  });

  await browser.close();
  return Buffer.from(pdf);
}

// Express endpoint
app.get('/api/invoice/:id/pdf', async (req, res) => {
  const invoice = await getInvoice(req.params.id);
  const html = renderInvoiceHtml(invoice);
  const pdf = await generatePdf(html);
  res.contentType('application/pdf');
  res.setHeader('Content-Disposition', `attachment; filename="invoice-${invoice.number}.pdf"`);
  res.send(pdf);
});

PDFKit(Node.js — 编程生成)

import PDFDocument from 'pdfkit';

function createInvoicePdf(invoice: Invoice): Promise<Buffer> {
  return new Promise((resolve) => {
    const doc = new PDFDocument({ size: 'A4', margin: 50 });
    const chunks: Buffer[] = [];
    doc.on('data', (chunk) => chunks.push(chunk));
    doc.on('end', () => resolve(Buffer.concat(chunks)));

    // Header
    doc.fontSize(20).text('INVOICE', { align: 'right' });
    doc.fontSize(10).text(`#${invoice.number}`, { align: 'right' });
    doc.moveDown();

    // Table
    doc.fontSize(12).text('Item', 50, doc.y);
    doc.text('Amount', 400, doc.y - 12, { width: 100, align: 'right' });
    doc.moveTo(50, doc.y).lineTo(550, doc.y).stroke();

    for (const item of invoice.items) {
      doc.text(item.description, 50, doc.y + 5);
      doc.text(`$${item.amount.toFixed(2)}`, 400, doc.y - 12, { width: 100, align: 'right' });
    }

    doc.end();
  });
}

@react-pdf/renderer(将 React 组件转换为 PDF)

import { Document, Page, Text, View, StyleSheet, renderToBuffer } from '@react-pdf/renderer';

const styles = StyleSheet.create({
  page: { padding: 30 },
  title: { fontSize: 24, marginBottom: 20 },
  row: { flexDirection: 'row', justifyContent: 'space-between', marginBottom: 5 },
});

function InvoicePdf({ invoice }: { invoice: Invoice }) {
  return (
    <Document>
      <Page size="A4" style={styles.page}>
        <Text style={styles.title}>Invoice #{invoice.number}</Text>
        {invoice.items.map((item) => (
          <View key={item.id} style={styles.row}>
            <Text>{item.description}</Text>
            <Text>${item.amount.toFixed(2)}</Text>
          </View>
        ))}
      </Page>
    </Document>
  );
}

// Server-side render
const buffer = await renderToBuffer(<InvoicePdf invoice={invoice} />);

Python(ReportLab)

from reportlab.lib.pagesizes import A4
from reportlab.platypus import SimpleDocTemplate, Table, Paragraph
from reportlab.lib.styles import getSampleStyleSheet

def generate_invoice_pdf(invoice: dict, output_path: str):
    doc = SimpleDocTemplate(output_path, pagesize=A4)
    styles = getSampleStyleSheet()
    elements = []

    elements.append(Paragraph(f"Invoice #{invoice['number']}", styles['Title']))

    data = [['Item', 'Amount']]
    for item in invoice['items']:
        data.append([item['description'], f"${item['amount']:.2f}"])

    table = Table(data, colWidths=[350, 100])
    elements.append(table)
    doc.build(elements)

反模式

反模式修复方法
每次生成 PDF 请求都启动新的浏览器重用浏览器实例,并创建新页面
生成 PDF 时未设置超时设置 page.setDefaultTimeout() 并中止操作
在请求处理中同步生成 PDF使用后台作业队列
HTML 模板中使用内联 CSS使用嵌入式 <style> 或设置 printBackground: true
未清理内存使用后关闭页面,并限制并发生成数量

生产环境检查清单

  • 浏览器实例池化(Puppeteer/Playwright)
  • 在后台队列中生成 PDF
  • 配置内存限制和超时
  • 将生成的 PDF 存储在对象存储中(S3)
  • 下载时设置 Content-Disposition 标头
  • 如需归档,确保符合 PDF/A 标准

评论

支持 Markdown