Skip to content

Instantly share code, notes, and snippets.

@tatsuyasusukida
Last active July 12, 2022 01:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tatsuyasusukida/fc83f928ec4c849b228b4474a9c0b9d4 to your computer and use it in GitHub Desktop.
Save tatsuyasusukida/fc83f928ec4c849b228b4474a9c0b9d4 to your computer and use it in GitHub Desktop.
πŸ“œ Puppeteer HTML to PDF converter
/node_modules/
/.env
/test.pdf
PORT=3000
PUPPETEER_SANDBOX=1
#PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome-stable
/node_modules/
/test.pdf
/package-lock.json
# Do not ignore package-lock.json other than gist
import puppeteer from 'puppeteer'
export default async function apiRender (req, res, next) {
try {
const chunks = []
await new Promise((resolve, reject) => {
req.on('data', chunk => chunks.push(chunk))
req.on('end', resolve)
req.on('error', reject)
})
const buffer = Buffer.concat(chunks)
const html = buffer.toString()
const args = process.env.PUPPETEER_SANDBOX === '1'
? []
: ['--no-sandbox'] // <1>
const browser = await puppeteer.launch({args})
try {
const page = await browser.newPage()
const options = {waitUntil: 'networkidle0'} // <2>
await page.setContent(html, options)
const buffer = await page.pdf()
res.type('pdf').send(buffer)
} finally {
await browser.close()
}
res.status(501).end()
} catch (err) {
next(err)
}
}
FROM node:lts-slim
RUN apt-get update \
&& apt-get install -y wget gnupg \
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
&& apt-get update \
&& apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "main.mjs"]
import express from 'express'
import apiRender from './api-render.mjs'
main()
function main () {
try {
const router = express()
router.post('/api/render', apiRender)
router.use((req, res) => res.status(404).end())
router.use((err, req, res, next) => {
res.status(err.status || 500).end()
console.error(err)
})
const port = process.env.PORT || '3000'
router.listen(port, () => {
console.info(`Listening on ${port}`)
})
} catch (err) {
console.error(err)
}
}
{
"name": "puppeteer-html2pdf",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node main.js",
"dev": "nodemon -r dotenv/config main.mjs",
"test": "cat test.html | curl http://localhost:3000/api/render -X POST --data-binary @- -v > test.pdf",
"build": "docker image build -t puppeteer-html2pdf .",
"serve": "docker container run --init -it --rm --name puppeteer-html2pdf --env PORT=3000 --env PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome-stable -p 3000:3000 puppeteer-html2pdf",
"image": "echo asia-northeast1-docker.pkg.dev/`gcloud config get-value project`/cloud-run/puppeteer-html2pdf",
"tag": "docker tag puppeteer-html2pdf `npm run -s image`",
"push": "docker push `npm run -s image`",
"deploy": "gcloud run deploy puppeteer-html2pdf --image `npm run -s image` --region asia-northeast1 --platform managed --allow-unauthenticated --set-env-vars 'PUPPETEER_EXECUTABLE_PATH=/usr/bin/google-chrome-stable'",
"staging": "npm run build && npm run tag && npm run push && npm run deploy",
"delete": "gcloud run services delete puppeteer-html2pdf --region asia-northeast1 --platform managed"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"dotenv": "^16.0.1",
"express": "^4.18.1",
"puppeteer": "^15.3.2"
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Puppeteer HTML to PDF converter</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans&family=Noto+Sans+JP&display=swap" rel="stylesheet">
<style>
@page {
margin: 20mm 20mm 20mm 20mm;
size: A4 portrait;
}
body {
font-family: 'Noto Sans', 'Noto Sans JP', sans-serif;
}
</style>
</head>
<body>
<h1>Puppeteer HTML to PDF converter</h1>
<p>ζ—₯本θͺžγ‚‚εˆ©η”¨ε―能です。</p>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment