前言
- 最近去了公司另外一个项目组工作
- 这个项目组实现打印的方式很有趣,是使用puppeteer这一插件,操纵chrome来生成和转化pdf文件,随后将生成文件传回前端
- 由于这个node服务的部署还没有完成docker化,所以本地环境配置与线上环境配置会有不一样的情况,最显著的就是chrome版本的差异,而这个差异则导致了后续的问题
问题的出现
- 本来是一个很简单的需求,只需要实现一页一个面单,并且使打印内容水平垂直居中即可
- 说到水平垂直居中,第一个想到的自然是flex布局
<div class="contanier">
<div class="content">内容</div>
</div>
<style>
.contanier {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.content {
}
</style>
- 如上,利用flex布局,可以很简单和方便的实现一个水平垂直居中的效果
- 很快的搞定手工,本地测试了一下打印效果,没有问题,上线验证
- 结果一上线就有用户反馈有打印偏移和空白页的问题,让我一下傻了眼
- 没办法,开始排查这个问题,一开始我以为是node服务对flex布局水土不服,于是乎我换了一种水平居中样式,利用transform来实现水平居中的样式
<div class="contanier">
<div class="content">内容</div>
</div>
<style>
.contanier {
position: relative;
}
.content {
position: relative;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
</style>
- 如上是利用transform来实现水平居中的样式
- 本地调试,测试通过,接着又将其上线,结果发现又有打印偏移和空白页的问题
chorome版本升级,服务端排查问题
- 这下应该不是样式的问题了,开始排查本地和线上的环境配置差异,后续通过控制变量,排除法,找出本地与线上的差异在于chrome版本
- 无奈开始排查线上服务端的问题,抓了位后端同学,帮忙看了一下线上机器上的chrome,发现线上机器的chrome处于102版本,而我本地的chrome是120版本,那很明显就能发现问题所在之处了
- 于是乎,我开始尝试通过升级服务器上的chrome版本来解决问题
- 先用测试环境的机子测试升级chrome的效果
- 机器环境为centos,使用yum安装软件
- 使用
yum update google-chrome-stable
命令,升级机器上的chrome
- 升级完毕,重启node服务,结果发现打印报错了
nodejs.Error: Failed to launch the browser process!
shell-init: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
[ERROR:headless_shell.cc(266)] Multiple targets are not supported.
TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md
yum install alsa-lib.x86_64 atk.x86_64 cups-libs.x86_64 gtk3.x86_64 ipa-gothic-fonts libXcomposite.x86_64 libXcursor.x86_64 libXdamage.x86_64 libXext.x86_64 libXi.x86_64 libXrandr.x86_64 libXScrnSaver.x86_64 libXtst.x86_64 pango.x86_64 xorg-x11-fonts-100dpi xorg-x11-fonts-75dpi xorg-x11-fonts-cyrillic xorg-x11-fonts-misc xorg-x11-fonts-Type1 xorg-x11-utils
yum update nss -y
- 执行完毕后,重启node服务,发现打印报错信息还是没变,看样子问题也不是出在依赖安装上
- 这下就头疼了,上网搜索也没有什么有用的信息
- 试着执行
google-chrome --headless --disable-gpu --print-to-pdf http://www.baidu.com --no-sandbox
命令,让chrome生成pdf
- 发现成功生成了pdf,那chorme的问题也能排除了
- 接着怀疑的对象来到了puppeteer,该项目使用的是puppeteer-core,为puppeteer的轻量版本,使用时需要注册chorme的路径,而路径的查找则使用了carlo库里的方法:carlo/lib/find_chrome,正巧报错信息里也有路径相关报错
- 想继续排查puppeteer和carlo库的问题,无奈时间有点久了,有同学跟我讲test环境其它人还要用,无奈只能终止,先把测试环境恢复
还原chorme版本
- 由于是升级chrome版本导致的问题,那最简单的办法则是回退chrome的版本
- 整个流程大致如下,卸载现有版本chrome,重装对应版本chrome
- 命令如下
yum remove google-chrome-stable
// 卸载成功后执行
sudo yum install ./google-chrome-stable-102.0.5005.115-1.x86_64.rpm
- 相关安装包可以在这里 找到
- 由于chrome处于安全考虑,官网是没有开放历史版本的下载的,所以为了找历史版本的安装包,也费了不少劲
- 谢天谢地,回退版本后没有问题了
- 经过这一番折腾,让我放弃了在服务端修复的想法
代码兼容
- 经过上面的一番折腾,也是大致摸清了打印的一整套流程,前端传递对应的html给node服务,node服务通过puppeteer操纵chrome生成pdf,最后将pdf返回给前端
- 给自己本地安装了一份102版本的chrome,进行复现问题,果然,102版本的chrome在转换生成pdf会有问题,与线上一致
- 通过观察生成出来的pdf,可以发现每个打印内容的下面都会有一小部分内容溢出,而正是这一点点的内容溢出,导致了打印偏移和空白页现象
- 打印的分页是通过css来控制的
@media print {
// 定义每页的高度
@page {
size: ${pageSizeWidth}mm ${pageSizeHeight}mm;
}
// 定义每个打印项的样式
.preview-item {
break-inside: avoid;
overflow: hidden;
height:${pageSizeHeight}mm;
width:${pageSizeWidth}mm;
padding:0;
}
}
- 如上这是我原本的写法,正常来讲,打印项的宽高与页的宽高严格相等,且设置了overflow属性为hidden,就能够保证打印内容不会溢出,且实现每页一个打印项的需求,可惜102版本的chrome在这种情况下转换pdf会有内容溢出的毛病
- 既然有一丢丢的内容溢出,那兼容的写法就很容易想到和实现了
- 改后的代码
@media print {
// 定义每页的高度
@page {
size: ${pageSizeWidth}mm ${pageSizeHeight}mm;
}
// 定义每个打印项的样式
.preview-item {
break-inside: avoid;
overflow: hidden;
height:${pageSizeHeight-1}mm;
width:${pageSizeWidth}mm;
padding:0;
}
}
- 可以看到我给打印项的高度减了1mm,而正是这1mm的削减,阻止了内容溢出的问题
- 也不用担心减了1mm后会出现上移的问题,打印项中break-inside属性,阻止了打印项被分页成两半,还是保证了一页一个打印项的需求
- 说实话这么改之后,其它前端同学还不太相信就这么减了1mm就解决了这个问题😂
- 修复上线,果然生产上就没有打印偏移和空白页的问题了,可喜可贺🎉🎉🎉