DEV Community

Cover image for Reliable Puppeteer Container Setup for PDF Generation
Wolfgang Rathgeb
Wolfgang Rathgeb

Posted on • Originally published at dropanote.de

Reliable Puppeteer Container Setup for PDF Generation

When developing PDF generation for a warehouse management system, I tried using the official Puppeteer container to reduce configuration complexity. I had developed everything locally first, and it worked perfectly.

But when I deployed with the container, all spacing disappeared - margins, padding, everything was compressed. The PDF generation logic still worked, but the layout was completely broken.

Puppeteer Container Spacing Issues

Puppeteer PDF output compare from differnt Dockerfile

I tried different Puppeteer configurations and researched the problem extensively. After multiple research sessions, AI conversations, and attempts with various configurations, nothing fixed the spacing issues.

Initially, it wasn't clear whether this was a general container problem or something specific to the official Puppeteer container. The simplest way to evaluate this was building my own container with Chromium installed. Most web tutorials were unnecessarily complex, and it turned out that a simple Chromium installation with proper Puppeteer configuration is completely sufficient.

When I tested this approach, the spacing issues disappeared completely, confirming it was specifically a problem with the official Puppeteer container.

My Working Solution

Here's my working Dockerfile that solves the spacing issues. The main part is in the first few lines - the rest is just standard Node.js setup:

# Use the official Node.js LTS image
FROM node:lts AS base
WORKDIR /usr/src/app

# Install Chromium manually
RUN apt-get update && apt-get install -y \
    chromium \
    && rm -rf /var/lib/apt/lists/*

# Multi-stage build for dependencies
FROM base AS install
RUN mkdir -p /temp/dev
COPY package.json package-lock.json /temp/dev/
RUN cd /temp/dev && npm ci

RUN mkdir -p /temp/prod
COPY package.json package-lock.json /temp/prod/
RUN cd /temp/prod && npm ci --production

FROM base AS prerelease
COPY --from=install /temp/dev/node_modules node_modules
COPY . .

ENV NODE_ENV=production
RUN npm run build

FROM base AS release
# Skip Puppeteer's bundled Chromium since we installed our own
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true

COPY --from=install /temp/prod/node_modules node_modules
COPY --from=prerelease /usr/src/app/build .
COPY --from=prerelease /usr/src/app/package.json .

ENV PORT=3733
EXPOSE 3733/tcp
USER node
ENTRYPOINT ["node", "./index.js"]
Enter fullscreen mode Exit fullscreen mode

When Puppeteer starts, it won't find its bundled Chrome version, so you need to tell it which browser to use. If you're using different environments with different Chrome installations, you can set this via environment variables. For local installations, setting the executablePath is not necessary.

The key configuration change in your Puppeteer code:

const browser = await puppeteer.launch({
  executablePath: "/usr/bin/chromium",
  args: ["--no-sandbox"],
});
Enter fullscreen mode Exit fullscreen mode

Note: --no-sandbox reduces security when processing untrusted content. For internal applications like warehouse systems, this trade-off is usually acceptable.

Updating Chromium Version

Keep in mind that Docker will use the cache for builds, so Chromium probably won't be updated with each build. This is fine for development because you save build time, but for production you'll want the current version:

docker build -t your-image-name --no-cache .
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
vishdrck profile image
Vishwajith Weerasinghe

I was looking for a solution for the same issue. Thanks mate