在 Node.js 中从 HTML 生成 PDF(以及我为何停止使用 Puppeteer)
Source: Dev.to
请提供您希望翻译的正文内容,我将为您翻译成简体中文。
实际上 Puppeteer 有哪些问题
- Memory – Chromium 是一个完整的浏览器。每个实例消耗 300–500 MB。如果渲染崩溃,浏览器进程可能无法清理,最终在真实流量下耗尽服务器内存。
- Cold starts – 启动一个 Chromium 实例需要 1–3 秒,每次都是如此。在会缩至零的无服务器函数上,这种延迟会影响第一个请求。
- Fonts and assets – Puppeteer 在沙箱中运行。任何从相对路径或
file://URL 加载的内容要么静默失败,要么渲染不正确。本地看起来正常的 PDF 在生产环境中可能出现破损。 - Server dependencies – Chromium 需要
libglib、libnss、libatk等库,而这些在普通的 Ubuntu 服务器上并不存在。每个新环境都成了全新的调试会话,Docker 镜像体积也会增加约 400 MB。
这些都不是 Puppeteer 的错;它是一个浏览器自动化工具,却被要求完成它本身并未真正设计去做的事情。
人们尝试的其他选项
wkhtmltopdf
使用 WebKit 渲染 HTML。它快速且轻量,无需管理浏览器进程。
缺点: 自 2020 年起未再维护;CSS 支持停留在 2013 年左右(不支持 flexbox、grid 或 CSS 变量)。现代布局会出现问题。
PDFKit / jsPDF
用代码描述文档——放置文本、绘制线条、设置字体。精确度高,适用于固定布局的文档。
缺点: 不能复用 HTML 模板。每次设计变更都需要修改代码,即使是带动态表格的简单发票也会变得冗长。
API
发送 HTML,返回 PDF。渲染基础设施由第三方处理——无需管理 Chromium、无需系统依赖、无需部署任何东西。大多数团队在尝试完其他方案后都会选择这种方式。
使用 API 实际的样子
const response = await fetch("https://lightningpdf.dev/api/v1/pdf/generate", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
html: `
发票 #1042
到期日:2026年3月31日
`,
options: { format: "A4" }
}) });
const { data } = await response.json(); const pdfBuffer = Buffer.from(data.pdf, “base64”);
就是这样。您现有的 HTML 模板可以直接使用,Tailwind 类无需构建步骤即可渲染,迁移自 Puppeteer 主要就是去掉浏览器的设置/拆卸代码。
## 可重复生成的文档模板
如果您需要生成结构固定的发票或报告,可以在可视化设计器中一次性创建模板,并在渲染时传入数据:
```js
body: JSON.stringify({
template_id: "invoice-001",
data: {
company: "Acme Corp",
invoice_number: "1042",
items: [
{ name: "Web development", quantity: 10, price: 150 },
{ name: "Design review", quantity: 2, price: 200 }
]
}
})
在应用代码中不需要进行 HTML 字符串拼接——模板独立存在,并在渲染时填充数据。
批量生成
对于批量作业(月末发票、报告运行),请使用异步端点,并在 PDF 准备好时接收 webhook:
const response = await fetch("https://lightningpdf.dev/api/v1/pdf/async", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json"
},
body: JSON.stringify({
template_id: "monthly-statement",
data: { user_id: "usr_123", month: "February" },
webhook_url: "https://yourapp.com/webhooks/pdf-ready"
})
});
粗略性能数据
| 方法 | 典型渲染时间 | 内存开销 |
|---|---|---|
| Puppeteer(自托管) | 2–4 秒 | 每实例 300–500 MB |
| wkhtmltopdf | 0.5–1 秒 | 低 |
| API(简单文档) | < 100 毫秒 | 与您无关 |
| API(复杂 CSS) | 1–3 秒 | 与您无关 |
对于简单文档,速度差异显著。Go 原生渲染器可以在 100 毫秒以内生成基本发票,而只有在处理复杂的 HTML/CSS 时才需要使用 Chromium。
对小项目来说值得吗?
可能是的,主要因为部署复杂性。即使你每月只生成 20 份 PDF,避免在每台服务器上安装 Chromium 也是有价值的。大多数 PDF API 都提供免费层,足以覆盖低流量。
对于实际流量或批量生成的情况,优势更为明显——你不再需要担心内存限制或进程管理。
你目前在使用什么工具进行 PDF 生成?如果你已经找到让自托管的 Puppeteer 在生产环境中良好运行的方法,欢迎分享经验。