之前的网页截图生成 PDF 项目使用的是 PhantomJS,由于其目前已停止开发,故切换到 puppeteer

运行环境准备

关于如何在 docker 中运行 puppeteer,官方文档中有详细说明(@Reference 1),这里仅以在 alpine 环境中运行举例。

FROM alpine

# Replace apk install source  for Chinese users.
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

# Installs latest Chromium (100) package.
RUN apk add --no-cache \
      chromium \
      nss \
      freetype \
      harfbuzz \
      ca-certificates \
      ttf-dejavu \
      fontconfig \
      nodejs \
      npm

# Tell Puppeteer to skip installing Chrome. We'll be using the installed package.
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true \
    PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser

# Puppeteer v13.5.0 works with Chromium 100.
RUN yarn add puppeteer@13.5.0

# Add user so we don't need --no-sandbox.
RUN addgroup -S pptruser && adduser -S -G pptruser pptruser \
    && mkdir -p /home/pptruser/Downloads /app \
    && chown -R pptruser:pptruser /home/pptruser \
    && chown -R pptruser:pptruser /app

# Run everything after as non-privileged user.
USER pptruser

这里需要 注意 的点:

  1. 只能够使用 apk 安装的 chromium,puppeteer 内置的脚本安装的 chromium 会有动态链接库不兼容的问题,因此一定要配置好 npm 安装依赖时的环境变量 PUPPETEER_SKIP_CHROMIUM_DOWNLOAD 和运行时的环境变量 PUPPETEER_EXECUTABLE_PATH
  2. 目前通过 apk 安装的 chromium 只支持在 puppeteer@13.5.0 下运行,因此需要检查好安装的 puppeteer 版本。
  3. 由于 alpine 中不含字体库,会导致 puppeteer 无法正常渲染文字,故添加 fontconfig 用于安装字体,需要将字体文件放置在 /usr/share/fonts/ 目录下。
  4. 国内用户使用 apk 安装库时可能会遇到网络问题,故可以切换 apk 源到国内镜像。

生成 PDF 示例代码

import puppeteer from 'puppeteer';

type Options = puppeteer.PDFOptions & {};

async function genPDF(content: string, options: Options) {
  const browser = await puppeteer.launch({
    args: [
      '--no-sandbox',
      '--disable-setuid-sandbox',
      // https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md#tips
      '--disable-dev-shm-usage',
    ],
  });
  const page = await browser.newPage();
  await page.setContent(content);
  const pdfBuffer = await page.pdf(options);
  await browser.close();
  return pdfBuffer;
}

Reference

  1. running-puppeteer-in-docker
  2. puppeteer API reference
  3. alpine linux 使用国内镜像源进行加速
  4. Alpine镜像的中文支持和字体对比(puppeteer自动截图)
  5. 如何给dcoker容器里的alpine系统安装中文字体