PDFエクスポートパターン
:LiTarget: 用途
HTMLレポートをPDFに変換してダウンロード/メール送信するパターン。
:LiSparkle: 特徴
- HTML→PDF変換
- スタイル保持
- メール送信
- ダウンロード
:LiCode: コード(コピペ用)
// クライアントサイドPDF生成(@react-pdf/renderer 不要・印刷API利用)
export async function exportToPDF(elementId: string, filename = 'report.pdf') {
const el = document.getElementById(elementId);
if (!el) throw new Error(`Element not found: #${elementId}`);
// 印刷用 iframe を生成
const iframe = document.createElement('iframe');
iframe.style.cssText = 'position:fixed;right:0;bottom:0;width:0;height:0;border:0';
document.body.appendChild(iframe);
const doc = iframe.contentWindow!.document;
doc.write(`<!DOCTYPE html><html><head><title>${filename}</title>`);
// 親ページのスタイルを継承
document.querySelectorAll('link[rel="stylesheet"], style').forEach((s) => {
doc.head.appendChild(s.cloneNode(true));
});
doc.write(`</head><body>${el.outerHTML}</body></html>`);
doc.close();
iframe.contentWindow!.focus();
iframe.contentWindow!.print();
setTimeout(() => document.body.removeChild(iframe), 1000);
}
// サーバサイド PDF(Cloudflare Workers + Browser Rendering)
export async function generatePDFServer(env: { BROWSER: any }, html: string): Promise<ArrayBuffer> {
const browser = await env.BROWSER.launch();
const page = await browser.newPage();
await page.setContent(html);
const pdf = await page.pdf({ format: 'A4', printBackground: true });
await browser.close();
return pdf;
}
// 使い方:
// <button onClick={() => exportToPDF('report-area', '月次レポート.pdf')}>PDF出力</button>
:LiHandPointer: 使い方
対象プロジェクトに該当ファイルをコピーして、props を流し込むだけ。
:LiAlertCircle: 注意事項
- 依存パッケージを忘れず追加