avatar

ShīnChvën ✨

Effective Accelerationism

Powered by Druid

Dockerized Puppeteer PDF Printer

Thu Mar 30 2023

Puppeteer provides solution to print PDF from web page. However, it requires a lot of dependencies to be installed. This post shows how to build a Docker image to run Puppeteer to print or generate PDF file.

Nodejs App To Print PDF Using Puppeteer

Puppeteer is a nodejs library that provides API to control headless Chrome or Chromium. Here's a piece of code to print PDF from a web page.

import { PDFOptions } from './../../node_modules/puppeteer-core/lib/cjs/puppeteer/common/PDFOptions.d';
import puppeteer from 'puppeteer';

const defaultPDFOptions: PDFOptions = {
  format: 'A4',
  margin: undefined,
};

export type WebPageToPdfArgs = {
  url: string, filepath: string,
  pdfOptions?: PDFOptions,
};

const webPageToPdf = async ({ url, filepath, pdfOptions }: WebPageToPdfArgs) => {
  const browser = await puppeteer.launch({
    headless: true,
    executablePath: 'google-chrome-stable', // use google-chrome-stable in docker
    args: ['--no-sandbox'], // required for running in docker as root
  });
  const page = await browser.newPage();
  await page.goto(url,
    { waitUntil: 'networkidle0' }
  );
  await page.pdf({
    ...(pdfOptions || defaultPDFOptions),
    path: filepath,
  });
  await browser.close();
  return filepath;
};

export default webPageToPdf;

Build a Docker Image to Run Puppeteer as a Service

Puppeteer uses Chromium or Chrome to print PDF, and it also requires a lot of dependencies to be installed. In the Dockerfile I added all the dependencies required by Puppeteer.

But when I try to run puppeteer in docker with bundled Chromium, an error occurred saying Chromium can not be found. So I decided to use google-chrome-stable instead of the bundled chromium.

Here's the Dockerfile.

FROM shinchven/node:16-deployment

# install dependencies for chrome and puppeteer
RUN apt update && apt install -y \
ca-certificates \
fonts-liberation \
libasound2 \
libatk-bridge2.0-0 \
libatk1.0-0 \
libc6 \
libcairo2 \
libcups2 \
libdbus-1-3 \
libexpat1 \
libfontconfig1 \
libgbm1 \
libgcc1 \
libglib2.0-0 \
libgtk-3-0 \
libnspr4 \
libnss3 \
libpango-1.0-0 \
libpangocairo-1.0-0 \
libstdc++6 \
libx11-6 \
libx11-xcb1 \
libxcb1 \
libxcomposite1 \
libxcursor1 \
libxdamage1 \
libxext6 \
libxfixes3 \
libxi6 \
libxrandr2 \
libxrender1 \
libxss1 \
libxtst6 \
lsb-release \
wget \
xdg-utils \
curl

# install google-chrome-stable, to use it, set executablePath to 'google-chrome-stable' in nodejs code
RUN curl -LO https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
RUN apt-get install -y ./google-chrome-stable_current_amd64.deb
RUN rm google-chrome-stable_current_amd64.deb

# copy files
WORKDIR /usr/src/app
COPY server /usr/src/app
# Put font files in /usr/share/fonts to fix character issues
COPY fonts/MSYH.ttc /usr/share/fonts/

# build app
RUN npm install && npm run compile

ENV NODE_ENV=production

EXPOSE 3030

CMD ["node","lib/index.js"]

web2pdf

With the code above, I created a GitHub repository web2pdf and a docker image shinchven/web2pdf. You can use it directly or build one of your own.