DEV Community

Gabriel de Paula Queiroz
Gabriel de Paula Queiroz

Posted on

6

GENERATE PDF with Puppeteer + Handlebars

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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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({})
... 



Enter fullscreen mode Exit fullscreen mode

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);


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

folders

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.

👋🏼

Image of Timescale

Timescale – the developer's data platform for modern apps, built on PostgreSQL

Timescale Cloud is PostgreSQL optimized for speed, scale, and performance. Over 3 million IoT, AI, crypto, and dev tool apps are powered by Timescale. Try it free today! No credit card required.

Try free

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Explore a sea of insights with this enlightening post, highly esteemed within the nurturing DEV Community. Coders of all stripes are invited to participate and contribute to our shared knowledge.

Expressing gratitude with a simple "thank you" can make a big impact. Leave your thanks in the comments!

On DEV, exchanging ideas smooths our way and strengthens our community bonds. Found this useful? A quick note of thanks to the author can mean a lot.

Okay