Welcome folks today in this blog post we will be generating a dynamic pdf document from the html5 template document using html5 and css3 in handlebars template. All the full source code of the application is shown below.
Get Started
In order to get started you need to initialize a new node.js
project using the below command as shown below
npm init -y
npm i puppeteer
And as you can see we are installing the puppeteer
library which is an automation library of node.js. And now we need to create the index.js
file which will be the starting point of the application as shown below
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
const puppeteer = require('puppeteer'); (async function() { try{ const browser = await puppeteer.launch() const page = await browser.newPage() await page.setContent('<h1>Hello World</h1>') await page.pdf({ path:'output.pdf', format:'A4', printBackground:true }) console.log("done creating pdf") await browser.close() process.exit() }catch(e){ console.log(e) } })() |
As you can see we are importing the puppeteer
library of node.js
. And then we are defining the async function where we are launching the puppeteer
library using the launch()
method and then we are opening the new page inside the browser using the newPage()
method and then we are setting the contents of the raw html
in the page using the setContent()
method. Here in the argument we are passing the <h1>
heading inside it. And then we are exporting that page html content to pdf document using the pdf()
method. Here we are passing the three options which is the path of the output pdf file where you want to store it. And then we are specifying the format of the pdf document which is A4
and then we are setting the printBackground
boolean parameter to true. And then we are closing the browser automatically using the close()
method in puppeteer.
And now if you execute the node.js
application in the terminal using the below command as shown below
node index.js
As you can see after executing the node.js
app then the output.pdf
file will be created in the root directory. And if you open the output.pdf
file in the browser. It will look something like this as shown below
Exporting HTML5 Template to PDF Using Handlebars
Now we will be exporting the dynamic
html5 template to pdf document using handlebars. For this you need to install the below libraries using the below command as shown below
npm i handlebars
npm i fs-extra
As you can see we are installing the above libraries which are handlebars
which is actually a template engine for embedding dynamic html5 templates and also we are installing the fs-extra
module which is installing the file system
module.
First of all we will be showing you the directory structure of the node.js
app as shown below
As you can see first of all we need to make the data.json
file where we will be defining all the user records which will be the array of objects where each user object will be having three properties which is name,age and country. So now create this data.json
file as shown below
data.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
{ "title":"PDF Document in Puppeteer & Handlebars", "users":[ { "name":"Kane Williamson", "age":32, "country":"New Zealand" }, { "name":"Martin Guptill", "age":35, "country":"New Zealand" }, { "name":"Finn Allen", "age":22, "country":"New Zealand" }, { "name":"Trent Boult", "age":32, "country":"New Zealand" }, { "name":"Tim Southee", "age":33, "country":"New Zealand" }, { "name":"Ross Taylor", "age":38, "country":"New Zealand" }, { "name":"Blair Tickner", "age":29, "country":"New Zealand" } ] } |
Now we need to import
this data.json inside the index.js
file and also import the handlebars
template as you can see
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
const hbs = require('handlebars') const fs = require('fs-extra') const path = require('path') const data = require('./data.json') const compile = async function (templateName,data){ const filePath = path.join(process.cwd(),'templates',`${templateName}.hbs`) const html = await fs.readFile(filePath,'utf8') return hbs.compile(html)(data) }; |
As you can see we are also importing the fs-extra
module and also we are importing the handlebars
module also and then we are also importing the path module as well. And then we are also importing the data.json
file. And then we are defining the compile
method in which we have two arguments inside it. It takes the actual handlebars template and also the data passed to it. That data will be the actual json data that you have defined inside the data.json
file. And inside this function we are first of all we are getting the filePath of the handlebars
template which is stored inside the templates
folder. And also after that we are reading all the html
which we have defined inside the handlebars
template and then we are using the compile
method of handlebars
library and in this function we are passing the template
and the data
.
Now we need to define the templates
folder and inside that we need to define the index.hbs
file and copy paste the below code
templates/index.hbs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{title}}</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"> </head> <body> <div class="container"> <h1 class="text-center"> {{title}} </h1> <table class="table"> <thead> <tr> <th>Name</th> <th>Age</th> <th>Country</th> </tr> </thead> <tbody> {{#each users as | user |}} <tr> <td>{{user.name}}</td> <td>{{user.age}}</td> <td>{{user.country}}</td> </tr> {{/each}} </tbody> </table> </div> </body> </html> |
As you can see we are importing the bootstrap 4
library cdn and also we are embedding the dynamic
title and also the users
array of objects using the {{}}
syntax. And then we are using the each
loop of handlebars. And then we are rendering the data inside the bootstrap 4 table. We are looping through the user properties and displaying the name
age and country
.
And then lastly we will be using the compile
method in puppeteer to call this function and pass the template and the data as shown below
1 2 3 |
const content = await compile('index',data) await page.setContent(content) |
As you can see we are calling the compile
method that we have defined and then we are passing the index.hbs
template and in the second argument we are passing the actual
user array of objects as the data. And then we are setting the content inside the page using the SetContent() method and then we are passing the content as an argument.
Now if you run your node.js app you will see the below result as shown below
node index.js
Full Source Code
Wrapping the blog post this is the full source code of the index.js
file as shown below
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
const puppeteer = require('puppeteer'); const hbs = require('handlebars') const fs = require('fs-extra') const path = require('path') const data = require('./data.json') const compile = async function (templateName,data){ const filePath = path.join(process.cwd(),'templates',`${templateName}.hbs`) const html = await fs.readFile(filePath,'utf8') return hbs.compile(html)(data) }; (async function() { try{ const browser = await puppeteer.launch() const page = await browser.newPage() const content = await compile('index',data) await page.setContent(content) await page.pdf({ path:'output.pdf', format:'A4', printBackground:true }) console.log("done creating pdf") await browser.close() process.exit() }catch(e){ console.log(e) } })(); |