puppeteer出现生成pdf分页偏移问题

2024-1-18 03:41:41

#前端#linux

9

前言

  • 最近去了公司另外一个项目组工作
  • 这个项目组实现打印的方式很有趣,是使用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就解决了这个问题😂
  • 修复上线,果然生产上就没有打印偏移和空白页的问题了,可喜可贺🎉🎉🎉