CSS and Image not showing in rendered pdf using html-pdf-node

Viewed 4083

I am trying to generate html to pdf in Node.js using html-pdf-node package. The page is working fine if I open the html file in the browser but when I generate it to pdf using html-pdf-node, the images and the css is not rendered in the pdf.

Here is my code:

template.html

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Bootstrap Example</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" type='text/css' href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
  <link rel="stylesheet" type='text/css' href="../css/style.css">
</head>
<body>

<div class="container">
  <div class="text-center">
    <img src="../images/logo.png" class="img-fluid" alt="Logo image">
  </div>
  

  <div class="container align-items-center atd-title text-center">
    <h3>Title Here</h3>
  </div>
  
  <div class="container align-items-center atd-container">
    <div class="row">
      <div class="col-lg-12">
        <p>Sir:</p>
        <p class="atd-paragraph">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </p>
      </div>
    </div>
  </div>
</div>

</body>
</html>

service.js

let fs = require('fs');
let path = require('path');
let ejs = require('ejs');
let html_to_pdf = require('html-pdf-node');

// Read HTML Template
let template = fs.readFileSync(path.resolve(__dirname, "../path/to/template.html"), 'utf8');
                
let html = ejs.render(template, {name: "test"});
let options = { format: 'A4' };
let file = { content: html };
let pdf = await html_to_pdf.generatePdf(file, options);
return pdf;
1 Answers

That's because the HTML string is being passed to html-pdf-node, the other assets like images and CSS are not. html-pdf-node uses Puppeteer as a headless browser to render the web page before saving it as PDF, when it tries to resolve the assets it sends HTTP requests that just fail.

You have two options to solve this:

  • Create a standalone HTML file with inline CSS and images as data URLs
  • Open a web server so that the assets can be resolved without being embedded

The simplest option is the second one, here is a minimal example:

const express = require('express')
const html_to_pdf = require('html-pdf-node')
const ejs = require('ejs')
const fs = require('fs')
const path = require('path')

const app = express()
const port = 3000

const template = fs.readFileSync(path.resolve(__dirname, "./index.html"), 'utf8')
const content = ejs.render(template, { title: "Awesome title!" })
fs.writeFile(path.resolve(__dirname, "./public/index.html"), content, () => {
    app.use(express.static('src/public'))

    const server = app.listen(port, async () => {
        const url = `http://localhost:${port}`
        const options = { format: 'A4', path: 'output.pdf' }
        const file = { url }
        await html_to_pdf.generatePdf(file, options)

        server.close()
    })
})

I've created a working project here: https://github.com/Guerric-P/html-pdf-node-demo

Related