GENERATE PDF with Puppeteer + Handlebars
Tags: puppeteer, handlebars, pdf, generate
Published: 2023-02-07 19:00:11

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

```js
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.

```js
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

```js
...
	// 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.

```js
	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:

```js
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();
```

![folders](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ushz7xewm9hbz95p3h9y.png)

**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.

**👋🏼**