三步用 html-pdf-chrome 把 HTML 转成 PDF:CreateOptions 实战指南
2026/8/22 21:38:22 网站建设 项目流程

三步用 html-pdf-chrome 把 HTML 转成 PDF:CreateOptions 实战指南

【免费下载链接】html-pdf-chromeHTML to PDF or image (jpeg, png, webp) converter via Chrome/Chromium项目地址: https://gitcode.com/gh_mirrors/ht/html-pdf-chrome

html-pdf-chrome 是一款基于无头 Chrome 的 HTML 转 PDF 库。它让真实 Chrome 内核渲染你的页面,再输出 PDF 或 PNG、JPEG、WebP 图片,适合报表生成、数据导出、网页存档等自动化场景。

手工转换 HTML 的麻烦在哪

先看看没有工具时,你平时是怎么干的:

  • 手动截图:浏览器打开页面,用截图工具截一张,长页面根本截不全,分辨率也不可控。
  • 打印成 PDF:用浏览器"打印为 PDF",页边距、纸张方向每次都要手点,没法写进脚本。
  • 定期报表:定时任务已经能生成 HTML 模板,但"转 PDF 并发邮件"这一步只能靠人,全自动无从谈起。

共同点是:这些操作要么不可重复,要么无法参数化。html-pdf-chrome 的做法是用一行create()调用替代它们,所有版式细节都通过CreateOptions对象用代码描述。

上手体验:三步拿到第一份 PDF

第一步,安装依赖:npm install html-pdf-chrome

第二步,让 Chrome 以无头模式监听调试端口:

chrome --headless --disable-gpu --remote-debugging-port=9222

第三步,调库生成文件:

import * as htmlPdf from 'html-pdf-chrome'; const options: htmlPdf.CreateOptions = { port: 9222, // 指向常驻 Chrome 的调试端口 }; // 传 HTML 字符串或 URL 都可以,返回结果对象 const result = await htmlPdf.create('<h1>Hello PDF</h1>', options); await result.toFile('first.pdf'); // 也可以 toBuffer()/toStream()/toBase64()

如果hostport都不传,库会为这一次生成临时启动一个 Chrome 实例,用完即关。能复用就复用,启动开销能省则省。

按场景整理配置参数

所有可选项集中在CreateOptions接口里,类型定义见源码文件src/CreateOptions.ts。逐项背参数效率低,按场景分组记更容易。

页面版式:方向、边距与纸张设置

printOptions直接对应 Chrome 的打印参数。scale就像打印机的缩放比例,小于 1 时内容整体缩小、能塞进更多行:

printOptions: { landscape: false, // false 纵向;宽表格改 true 横向 paperWidth: 8.27, // 纸张宽度(英寸),A4 约 8.27 x 11.69 paperHeight: 11.69, marginTop: 0.4, // 四边距单位都是英寸,留白太大会浪费纸 marginBottom: 0.4, marginLeft: 0.4, marginRight: 0.4, scale: 1.0, displayHeaderFooter: true, // 页眉页脚模板生效的前提 headerTemplate: '<span class="pageNumber"></span>', // 内置占位符:pageNumber/totalPages/title }
参数说明建议值
landscape纸张方向报表用false,宽表用true
paperWidth/paperHeight纸张尺寸(英寸)A4:8.27 x 11.69;Letter:8.5 x 11
marginTop等四个边距页面留白0.3 ~ 0.5
scale打印缩放0.8 ~ 1.0
headerTemplate/footerTemplate页眉页脚 HTML 模板displayHeaderFooter一起开启

输出格式:PDF 还是图片

默认输出 PDF;只要传了screenshotOptions,输出就变成图片。deviceMetrics决定"浏览器窗口"多大,相当于先决定取景框再拍照:

screenshotOptions: { format: 'jpeg', // png / jpeg / webp quality: 85, // 仅 jpeg 生效,1-100 clip: { x: 0, y: 0, width: 800, height: 600 }, // 只截这一块区域 }, deviceMetrics: { width: 1200, // 视口宽度 height: 800, deviceScaleFactor: 2, // 2 倍像素,图更清晰但文件更大 mobile: false, }
参数类型说明
screenshotOptions.format'png' \| 'jpeg' \| 'webp'图片格式,默认 png
screenshotOptions.qualitynumber仅 jpeg 有效的压缩质量
screenshotOptions.clipobject裁剪区域,不传则截整个视口
deviceMetrics.deviceScaleFactornumber像素密度,2 表示 2 倍清晰度

页面就绪等待:completionTrigger

这是新手最容易踩的点:页面 JS 还没取完数据,PDF 就先转好了,产出的是一张"空壳"。解决办法是用completionTrigger告诉库"等到什么信号再打印":

// 等待 id 为 dataLoaded 的节点出现,最多等 10 秒 completionTrigger: new htmlPdf.CompletionTrigger.Element('#dataLoaded', 10000)
触发器适用场景
Timer(毫秒)内容加载耗时基本固定,最省事
Element(css选择器)等某个数据节点渲染出来
Event(事件名)页面里自己 dispatch 完成事件
LifecycleEvent('networkIdle')请求密集,等网络空闲
Variable('变量名')前端把变量置 true 表示完成
Callback('回调名')前端主动调用约定好的回调

头部与身份:请求头和 Cookie

页面需要登录态或带 token 才能拿到数据时,用这两项把身份带过去:

extraHTTPHeaders: { 'Authorization': 'Bearer xxx', // 随每次请求发出 }, cookies: [ { name: 'session', value: 'abc', domain: '.example.com' }, // 预置登录态 ], clearCache: true // 加载前清缓存,防止渲染到旧内容

错误捕获:看到页面里发生了什么

无头 Chrome 里没人盯着控制台,页面报错不会有任何提示。挂上两个回调,页面内部的消息会转发到你的 Node 进程:

runtimeConsoleHandler: (event) => { // 页面的 console.log / warn / error 都会到这里 console.log('页面控制台:', event.type, event.args); }, runtimeExceptionHandler: (exception) => { // 捕获未处理的异常,排查白屏利器 console.error('页面异常:', exception.exceptionDetails); }, timeout: 30000 // 整体超时(毫秒),防止无限等待

两个实战案例

案例 1:带认证头的报表 PDF

const options: htmlPdf.CreateOptions = { port: 9222, printOptions: { landscape: true, // 报表列多,用横向 printBackground: true, // 保留表头背景色 marginTop: 0.5, marginBottom: 0.5, marginLeft: 0.5, marginRight: 0.5, }, extraHTTPHeaders: { 'Authorization': 'Bearer report-token' }, completionTrigger: new htmlPdf.CompletionTrigger.Timer(2000), timeout: 60000, // 数据量大,超时放宽 }; const html = await renderReportTemplate(); // 模板引擎生成 HTML const pdf = await htmlPdf.create(html, options); await pdf.toFile('monthly-report.pdf');

案例 2:移动端视口截图

const options: htmlPdf.CreateOptions = { port: 9222, screenshotOptions: { format: 'jpeg', quality: 85 }, deviceMetrics: { width: 375, // 常见手机视口宽度 height: 667, deviceScaleFactor: 2, mobile: true, // 模拟移动设备,CSS 媒体查询按手机端匹配 }, completionTrigger: new htmlPdf.CompletionTrigger.LifecycleEvent('networkIdle'), }; const result = await htmlPdf.create('https://example.com', options); await result.toFile('mobile-view.jpg');

避坑指南 🚧

现象:导出的 PDF 内容是空壳或半截原因:动态内容还没渲染完就触发了转换。 解决:按页面特性选completionTrigger——有明确节点用Element,请求多用LifecycleEvent('networkIdle'),并给足超时时间。

现象:报连接失败,create 直接抛错原因:Chrome 没启动,或调试端口没开、端口号对不上。 解决:先执行chrome --headless --disable-gpu --remote-debugging-port=9222,再让options.port与之一致。

现象:PDF 中文乱码原因:HTML 没声明字符集,渲染时编码猜错。 解决:在文档头部加<meta charset="UTF-8">

现象:长时间运行后 Chrome 越来越卡、内存持续增长原因:同一个实例反复生成页面,内存慢慢累积。 解决:用 pm2 这类进程管理器让 Chrome 常驻并崩溃自动拉起,同时定期重启实例。

现象:每生成一份 PDF 要多等好几秒原因:没配host/port,每次都在临时启动一个新的 Chrome。 解决:让 Chrome 常驻,CreateOptions里指定端口复用,这是无头 Chrome 生成 PDF 最主要的提速手段。

速查卡

场景关键参数建议值
复用常驻 Chromehost/portport: 9222
A4 纵向报表printOptions纵向 + 边距 0.3~0.5 英寸
横向宽表printOptions.landscapetrue
页码页眉displayHeaderFooter+ 模板pageNumber/totalPages占位符
导出图片screenshotOptionsformat: 'png'/'jpeg'/'webp'
2 倍清晰度deviceMetrics.deviceScaleFactor2
数据驱动页面completionTrigger.Element等待数据节点,超时 10 秒
请求密集页面completionTrigger.LifecycleEvent'networkIdle'
需登录态extraHTTPHeaders/cookies传 token 或会话 Cookie
长耗时任务timeout30 ~ 60 秒

配置的核心其实就三块:port决定连哪个 Chrome,printOptions决定版式,completionTrigger决定什么时候动手。把这三块理顺,html-pdf-chrome 就能覆盖绝大多数 HTML 转 PDF 的需求;参数细节可直接阅读src/CreateOptions.ts中的类型定义与注释。

【免费下载链接】html-pdf-chromeHTML to PDF or image (jpeg, png, webp) converter via Chrome/Chromium项目地址: https://gitcode.com/gh_mirrors/ht/html-pdf-chrome

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询