skip to Main Content

I’m using NodeJS (version 16.14.0) and puppeteer (version 13.4.1).

I want to create a local environment to get local html templates and produce pdfs from them. Doing it with static html is simple, but I still don’t understand how to generate dynamic data inside html templates to render (and generate) pdf with puppeteer. This is what i managed so far.

server.js (it’s just a test app, so for now im generating the pdf inside the server creation and run)

const express = require('express');
const path = require('path');
const puppeteer = require('puppeteer');
const app = express();
const PORT = 3000;

app.listen(PORT, function() {
    console.log(`nServer running on port ${PORT}n`);

    (async() => {    
        const browser = await puppeteer.launch();
        const page = await browser.newPage();    
        await page.goto(path.join(__dirname, 'pdf_templates', 'htmls', 'example1_template.html'));    
        await page.pdf({
            path: 'test.pdf',
            format: 'A4',
            margin: {
                top: "20px",
                left: "20px",
                right: "20px",
                bottom: "20px"
            }    
        });    

        await browser.close();    
    })();
});

Inside the pdf templates i got a template, a style and an image (in different folders below pdf_templates).

enter image description here

The (static for now) template is:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Example 1</title>
        <link rel="stylesheet" href="../styles/example1_style.css" media="all" />
    </head>
    <body>
        <header class="clearfix">
            <div id="logo">
                <img src="../images/example1_logo.png">
            </div>
            <h1>INVOICE 3-2-1</h1>
            <div id="company" class="clearfix">
                <div>Company Name</div>
                <div>455 Foggy Heights,<br /> AZ 85004, US</div>
                <div>(602) 519-0450</div>
                <div><a href="mailto:[email protected]">[email protected]</a></div>
            </div>
            <div id="project">
                <div><span>PROJECT</span> Website development</div>
                <div><span>CLIENT</span> John Doe</div>
                <div><span>ADDRESS</span> 796 Silver Harbour, TX 79273, US</div>
                <div><span>EMAIL</span> <a href="mailto:[email protected]">[email protected]</a></div>
                <div><span>DATE</span> August 17, 2015</div>
                <div><span>DUE DATE</span> September 17, 2015</div>
            </div>
        </header>
        <main>
            <table>
                <thead>
                    <tr>
                        <th class="service">SERVICE</th>
                        <th class="desc">DESCRIPTION</th>
                        <th>PRICE</th>
                        <th>QTY</th>
                        <th>TOTAL</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td class="service">Design</td>
                        <td class="desc">Creating a recognizable design solution based on the company's existing visual identity</td>
                        <td class="unit">$40.00</td>
                        <td class="qty">26</td>
                        <td class="total">$1,040.00</td>
                    </tr>
                    <tr>
                        <td class="service">Development</td>
                        <td class="desc">Developing a Content Management System-based Website</td>
                        <td class="unit">$40.00</td>
                        <td class="qty">80</td>
                        <td class="total">$3,200.00</td>
                    </tr>
                    <tr>
                        <td class="service">SEO</td>
                        <td class="desc">Optimize the site for search engines (SEO)</td>
                        <td class="unit">$40.00</td>
                        <td class="qty">20</td>
                        <td class="total">$800.00</td>
                    </tr>
                    <tr>
                        <td class="service">Training</td>
                        <td class="desc">Initial training sessions for staff responsible for uploading web content</td>
                        <td class="unit">$40.00</td>
                        <td class="qty">4</td>
                        <td class="total">$160.00</td>
                    </tr>
                    <tr>
                        <td colspan="4">SUBTOTAL</td>
                        <td class="total">$5,200.00</td>
                    </tr>
                    <tr>
                        <td colspan="4">TAX 25%</td>
                        <td class="total">$1,300.00</td>
                    </tr>
                    <tr>
                        <td colspan="4" class="grand total">GRAND TOTAL</td>
                        <td class="grand total">$6,500.00</td>
                    </tr>
                </tbody>
            </table>
            <div id="notices">
                <div>NOTICE:</div>
                <div class="notice">A finance charge of 1.5% will be made on unpaid balances after 30 days.</div>
            </div>
        </main>
        <footer>
            Invoice was created on a computer and is valid without the signature and seal.
        </footer>
    </body>
</html>

My question is: how can i inject dynamic data inside the html template through puppeteer? The idea is to get data from a database and the render the result in a structural html way and then generate the pdf of it.
Is that possible?

2

Answers


  1. Using puppeteer as templating engine is quiet novel idea to me.
    I don’t know exact usecase but I maybe look more for pdf templating engines (libraries). IE pdfkit (https://pdfkit.org)

    Regarding your solution.
    Simplest way I can think of is to place javascript inside the app, load the dada via REST API and use jQuery to generate the rows in the table.

    That’s the least effort I can think of, but I don’t know where your data are located and what your options are for loading them.

    Login or Signup to reply.
  2. I believe you’re mixing up technologies a bit.
    Puppeteer js is for headless or headless browser interactions. It would function as away to interact with the dom.

    If you have node setup on your own server then you can fs the file.
    Then create the pdf and replace any data with handlebars.
    An example: handlebars-pdf

    Example assuming you are manually filling out the html:

    let PDF = require('handlebars-pdf')
    let document = {
            template: '<h1>{{msg}}</h1>'+
            '<p style="color:red">Red text</p>'+
            '<img src="https://archive.org/services/img/image" />',
            context: {
                msg: 'Hello world'
            },
            path: "./test-"+Math.random()+".pdf"
        }
     
    pdf.create(document)
        .then(res => {
            console.log(res)
        })
        .catch(error => {
            console.error(error)
        })
    

    If you’re reading with fs it would be something like:

    const html_code = fs.readFileSync(`urlfileURL`)
    template: html_code
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search