Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert HTML to PDF or PNG without headeless browser instance in NodeJS

TL;DR:

  1. Any suggestions in NodeJS to convert an HTML to PDF or PNG without any headless browser instances.
  2. Also anyone uses puppeteer in any production environment. I would like to know how the resource utilisations and performance of running headless browser in prod.

Longer version:

In a NodeJS server we need to convert an HTML string to a PDF or PNG based on the request params. We are using puppeteer to generate this PDF and PNG (screenshot) deployed in a google cloud function. In my local running this application in a docker and restricted memory usage to 100MB and this seems working. But in cloud function it throws memory limit exception when we set the cloud function to 250MB memory. For a temporary solution we upgraded the cloud function to 1 GB.

We would like to try any alternatives for puppeteer without any headless browser approach. Another library PDF-Kit looks good but it have canvas api kind of input. We can't directly feed html.

Any thoughts or input on this

like image 439
Anand Prem Avatar asked Jan 19 '26 00:01

Anand Prem


1 Answers

If you can use Docker, then a great solution for you may be Gotenberg.

It's an incredible service that can convert a lot of formats (HTML, Markdown, Word, Excel, etc.) into PDF.

If your page render depends on JavaScript, then no problem, it will run it and wait (you can even configure the max wait time) for the page to be completely rendered to generate your PDF.

We are using it for an application that generates 3000 PDFs per day and never had any issue with it.

Demo:

Take a look at this sample HTML invoice: https://sparksuite.github.io/simple-html-invoice-template/

Now let's convert it to PDF:

enter image description here

Boom, done!

1: Gotenberg URL (here using a demo endpoint provided by Gotenberg team with some limitations like 2 requests per second per IP and 5MB body limit)

2: pass an url parameter with the URL of the webpage you want to convert

3: You get the PDF as the HTTP response with Content-Type application/pdf

Curl version:

curl --location --request POST 'https://demo.gotenberg.dev/forms/chromium/convert/url' \
--form 'url="https://sparksuite.github.io/simple-html-invoice-template/"' \
-o myfile.pdf

Node.JS version:

const fetch = require('node-fetch');
const FormData = require('form-data');
const fs = require('fs');

async function main() {
  const formData = new FormData();
  formData.append('url', 'https://sparksuite.github.io/simple-html-invoice-template/')
  const res = await fetch('https://demo.gotenberg.dev/forms/chromium/convert/url', {
    method: 'POST',
    body: formData
  })
  const pdfBuffer = await res.buffer()
  // You can do whatever you like with the pdfBuffer, such as writing it to the disk:
  fs.writeFileSync('/home/myfile.pdf', pdfBuffer);
}

main()

Using your own Docker instance instead of the demo endpoint, here is what you need to do:

1. Create the Gotenberg Docker container:

docker run -p 3333:3000 gotenberg/gotenberg:7 gotenberg

2. Call the http://localhost:3333/forms/chromium/convert/url endpoint:

enter image description here

Curl version:

curl --location --request POST 'http://localhost:3333/forms/chromium/convert/url' \ 
--form 'url="https://sparksuite.github.io/simple-html-invoice-template/"' \
-o myfile.pdf

Node.JS version:

const fetch = require('node-fetch');
const FormData = require('form-data');
const fs = require('fs');

async function main() {
  const formData = new FormData();
  formData.append('url', 'https://sparksuite.github.io/simple-html-invoice-template/')
  const res = await fetch('http://localhost:3333/forms/chromium/convert/url', {
    method: 'POST',
    body: formData
  })
  const pdfBuffer = await res.buffer()
  // You can do whatever you like with the pdfBuffer, such as writing it to the disk:
  fs.writeFileSync('/home/myfile.pdf', pdfBuffer);
}

main()

Gotenberg homepage: https://gotenberg.dev/

like image 177
Vincent Avatar answered Jan 21 '26 14:01

Vincent