GENERATE PDF with Puppeteer + Handlebars
Gabriel de Paula Queiroz
Posted on February 7, 2023
In this tutorial, we are going to learn how to generate a PDF using an API.
For this, we will use the following libs
Let's use the lib https://www.npmjs.com/package/puppeteer, which is a chromium for us to manipulate our HTML
We will also use the Handlebars lib https://www.npmjs.com/package/handlebars, which is basically a template compiler.
So the first step is to install these libraries, for that just run
npm install puppeteer handlebars
// or if you are using yarn
yarn install puppeteer handlebars
After installing the libraries, we will create a controller in our API by starting the puppeteer configuration.
class PDFController {
async index(_: Request, response: Response) {
// Defines the name of the PDF
const name = 'nodejs-pdf-example.pdf';
let configLaunch = {
headless: true, // headless:
Informs whether the browser should run headless, that is, without a graphical interface
ignoreDefaultArgs: ['--disable-extensions'],
};
// Start the puppeteer
const browser = await puppeteer.launch(configLaunch);
// Open new page
const page = await browser.newPage();
const waitUntil = 'networkidle2';
}
export default new PDFController();
Now, let's add our HTML, which will serve as the base of our PDF
...
// getting the template
const templateDir = resolve(__dirname, '..', 'views', 'template-pdf.hbs');
const file = fs.readFileSync(templateDir, 'utf-8');
// compiling
const fileCompiled = Handlebars.compile(file);
// getting the template in string
const fileHTML = fileCompiled({})
...
After that, let's integrate our HTML with the puppeteer. The puppeteer has his own method to generate the pdf.
await page.setContent(fileHTML, {
waitUntil,
});
await page.setDefaultNavigationTimeout(0);
// generate PDF
await page.pdf({
format: 'A4',
path: `tmp/${name}`,
displayHeaderFooter: false,
preferCSSPageSize: false,
printBackground: true,
});
await browser.close();
const pdfFile = fs.readFileSync(`tmp/${name}`);
// Removing PDF file from the temp folder
fs.unlinkSync(`tmp/${name}`);
// return the PDF
response.contentType('application/pdf');
response.send(pdfFile);
And the complete code should look like this:
import { Request, Response } from "express";
import puppeteer from "puppeteer";
import fs from 'fs'
import { resolve } from "path";
import Handlebars from "handlebars";
class PDFController {
async index(_: Request, response: Response) {
const name = 'nodejs-pdf-example.pdf';
let configLaunch = {
headless: true,
ignoreDefaultArgs: ['--disable-extensions'],
};
const browser = await puppeteer.launch(configLaunch);
const page = await browser.newPage();
const waitUntil = 'networkidle2';
const templateDir = resolve(__dirname, '..', 'views', 'template-pdf.hbs');
const file = fs.readFileSync(templateDir, 'utf-8');
const fileCompiled = Handlebars.compile(file);
const fileHTML = fileCompiled({})
await page.setContent(fileHTML, {
waitUntil,
});
await page.setDefaultNavigationTimeout(0);
await page.pdf({
format: 'A4',
path: `tmp/${name}`,
displayHeaderFooter: false,
preferCSSPageSize: false,
printBackground: true,
});
await browser.close();
const pdfFile = fs.readFileSync(`tmp/${name}`);
fs.unlinkSync(`tmp/${name}`);
response.contentType('application/pdf');
response.send(pdfFile);
}
export default new PDFController();
Hope I was able to help!
The full project directory is at: https://github.com/gabrielqueirozdev/nodejs-pdf-example
If you have any suggestions for improvement, please contact me.
👋🏼
Posted on February 7, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.