Egg + Puppeteer 实现Html转PDF
要一直向上,要保持满腔的热血
# 背景
项目组有个类似富文本编辑器功能,在 IE 浏览器下需要支持打印。为解决打印兼容性问题,需要一套根据 Html 输出 PDF 的服务。
so, 想直接看结果的: Html 转 PDF 在线预览 (opens new window) 😎😎😎
# 调研
html 转 pdf 方案有很多,怎么选择也看各位的具体情况
# 1、chrome 浏览器自带
# 缺点:
- 需要用户自己点击
- 用户需要使用 chrome 等支持的浏览器
- 打印默认是全局打印
广告:局部打印可以参考我的插件 😝😝😝: vue-iframe-print (opens new window)
npm install vue-iframe-print
在需要打印的 DOM 上加上v-print
即可实现局部打印
# 2、html2canvas + jsPdf
实现可参考:Javascript 将 html 转成 pdf,下载,支持多页哦(html2canvas 和 jsPDF) (opens new window)
# 缺点:
- html2canvas 插件在 IE 的兼容性问题
- 清晰度问题
- 分页问题
- 文字图片截断问题
# 3、node 服务端转换
- wkthtmltopdf (opens new window) 坑较多~
- phantomjs (opens new window) 基于 webkit 的无头浏览器,社区使用的不多,很久没更新了,可以深度了解下
- Puppeteer (opens new window) + Headless Chrome 社区里使用该方案的也比较多
# 选用 Egg + Puppeteer 😉😉😉
如果你想自己重头开始搭建,可以参考:puppeteer 生成 pdf,绝对解决你的需求 (opens new window)
# 部署(敲黑板)❗❗❗
当你已经完成了基本功能以后,高高兴兴的以为就剩下最后一步了,那么坑来了~
# 1、在 Docker 中使用 Puppeteer
官方文档指出“在 Docker 中使用 headless Chrome 并使其运行起来可能会非常棘手”。官方文档有疑难解答部分 (opens new window),你可以找到有关用 Docker 安装 puppeteer 的所有必要信息。
如果你在 Alpine 镜像上安装 Puppeteer,请确保在看到页面的这一部分时再向下滚动一点。否则你可能会忽略一个事实:你无法运行最新的 Puppeteer 版本,并且你还需要用一个标记禁用 shm
const browser = await puppeteer.launch({
headless: true,
args: ['--disable-dev-shm-usage']
});
2
3
4
否则,Puppeteer 子进程可能会在正常启动之前耗尽内存。
# 2、在 centOS 中部署
# 第一步:安装 chrome
因为是直接使用的 Puppeteer 包,需要依赖于 chrome 内核,所以你在启动项目npm install
的时候会一直卡在node install.js
这里,因为 china 网络问题和 chrome 太大,你很难在服务器上直接部署成功。
puppeteer 支持本地 chrome 安装链接,所以可以手动指定
跳过 chrome 安装:npm install puppeteer --ignore-scripts
chrome 安装具体可参考:阿里云服务器(centos7)的使用(7)一 Puppeteer 导出 PDF 的部署和使用 (opens new window)
# 坑出没,warning~
const browser = await puppeteer.launch({
args: ['--disable-dev-shm-usage', '--no-sandbox'],
headless:true,
// linux chrome的默认安装路径
executablePath:'/opt/google/chrome/chrome'
});
2
3
4
5
6
这里写的 puppeteer 启动路径executablePath
是 linux 下 chrome 的安装路径,如果换了本地,不同的系统对应的路径可能都不一样~ 千辛万苦找了一个包,很好用~ npm install carlo
关于carlo
,可以去了解下:『Carlo』 一个新的 Electron ? (opens new window)
'use strict';
const puppeteer = require('puppeteer');
const findChrome = require('../../node_modules/carlo/lib/find_chrome');
let browser = null;
module.exports = async () => {
if (!browser) {
const findChromePath = await findChrome({});
// browser = await puppeteer.launch();
browser = await puppeteer.launch({
headless: true,
// chrome的默认安装路径
executablePath: findChromePath.executablePath,
args: [
'--disable-gpu',
'--disable-dev-shm-usage',
'--disable-setuid-sandbox',
'--no-first-run',
'--no-sandbox',
'--no-zygote',
'--single-process',
],
});
}
return browser;
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 第二步:部署脚本
虽然 egg 有自己的进程管理,但是这里还是推荐使用 pm2,在项目根目录下
新建 deploy.sh
# 部署脚本
type node
npm install puppeteer --ignore-scripts
npm install
pm2 kill
# 睡眠,避免出现错误:Spawning PM2 daemon with pm2_home
sleep 2
pm2 start pm2.config.json
2
3
4
5
6
7
8
新建 pm2.config.json
{
"apps": [
{
"name": "html-to-pdf",
"script": "npm",
"args": "run start",
"log_date_format": "YYYY-MM-DD HH:mm:ss",
"exec_mode": "fork",
"max_memory_restart": "500M"
}
]
}
2
3
4
5
6
7
8
9
10
11
12
# 一切就绪,启动!!!
在服务器的项目中执行sh deploy.sh
, pm2 显示启动成功即可
这个时候服务是没问题了,但是其他问题就来了,因为服务器上是没有中文字体库的~所以生成的 pdf,中文字体全是乱码
# 第三步:安装字体
一、安装 fontconfig
yum -y install fontconfig
这个命令执行完成之后,就可以在/usr/share
文件夹里面看到 fonts 和 fontconfig
二、添加中文字体库
- 从 window 的
C:\Windows\Fonts
里面字体拷贝一份,或者只选择你需要的 - 在 CentOS 的
/usr/share/fonts
新建一个叫 chinese 的文件夹 - 然后把刚刚拷贝字体放到 CentOS 的
/usr/share/fonts/chinese
里面 - 修改 chinese 目录的权限。
chmod -R 775 /usr/share/fonts/chinese
- 接下来需要安装
ttmkfdir
来搜索目录中所有的字体信息,并汇总生成 fonts.scale 文件,输入命令yum -y install ttmkfdir
- 执行 ttmkfdir 命令,
ttmkfdir -e /usr/share/X11/fonts/encodings/encodings.dir
- 打开字体配置文件,
vi /etc/fonts/fonts.conf
,添加下面这一段
<!-- Font directory list -->
<dir>/usr/share/fonts</dir>
<dir>/usr/share/X11/fonts/Type1</dir>
<dir>/usr/share/X11/fonts/TTF</dir>
<dir>/usr/local/share/fonts</dir>
<dir>/usr/local/share/fonts/chinese</dir>
<dir>~/.fonts</dir>
2
3
4
5
6
7
- 刷新内存中的字体缓存,fc-cache
- 看一下现在机器上已经有了刚才添加的字体。fc-list :lang=zh
# 大功告成
这个时候基本就没问题了, 后续遇到的问题再更新。
# 最后:IE 加载 PDF
需要安装下 adobe reader
# 参考
- Javascript 将 html 转成 pdf,下载,支持多页哦(html2canvas 和 jsPDF) (opens new window)
- html 转 PDF 文件,完美解决方案——jsPDF,htmltocanvas,pdfmake,wkhtmltopdf,TuesPechkin,snappy (opens new window)
- 利用 puppeteer 和 egg.js 实现 html2pdf、html2png。 (opens new window)
- page.pdf([options]) (opens new window)
- 01
- 2023/07/03 00:00:00
- 02
- 2023/04/22 00:00:00
- 03
- 2023/02/16 00:00:00