If you're looking to create a pdf in Javascript within NodeJS, you've got 2 solutions :

  • You can either create, by hand, a PDF using a library like PDFKit for example
  • Or you can generate a PDF from a HTML document

I'm going to show you the second solution because it's faster, it allows you to easily edit the document layout and you benefit from the rendering power of HTML/CSS.

Using Puppeteer

It's possible to generate a pdf directly from the browser, by combining the library html2canvas to transform the DOM into an image, and then insert the resulting image into a PDF file.

But this solution has a wobbly rendering, is browser-dependant (looks different on different browsers) and the text can't be selected, because it's only available as an image.

By using Puppeteer, we're simply going to use the "Print as PDF" feature availble under Chromium, but in an automated way to get a perfectly rendered document !

As a reminder, Puppeteer is an headless browser, meaning it is able to do anything a regular browser can do, without displaying anything on the screen, which is allow us to automate many tasks like this one.

Puppeteer can also be used to crawl web pages as I explain in this other post I wrote on the blog (in French).

The code

First you'll need to install Puppeteer, to do so, we will use the following command:

npm install puppeteer
# or with yarn
yarn add puppeteer

Next, you will need to create the script that will load a web page (I personally chose one of my blog posts), then inject some CSS to hide some unwanted elements (header, cookie-bar, etc...) and finally generate our PDF!

//index.js
const puppeteer = require('puppeteer')
 
async function generatePDF() {

  //We start a new browser, without showing UI
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();
  const url = 'https://blog.nicolas.brondin-bernard.com/comment-resoudre-les-problemes-daccents-dans-vos-pages-web/';

  //We load the page, one of my blog post (networkidle0 means we're waiting for the network to stop making new calls for 500ms
  await page.goto(url, {waitUntil: 'networkidle0'});
  //We add style to hide some UI elements we don't want to see on our pdf
  await page.addStyleTag({ content:
    `header.site-header,
    #cookie-band,
    .post-full-image,
    .post-full-comments,
    .read-next,
    .site-footer { 
      display: none !important;
    }`
  });

  //Let's generate the pdf and close the browser
  const pdf = await page.pdf({ path: "article.pdf", format: 'A4' });
  await browser.close();
  return pdf;
}

generatePDF();

Thanks to this method, you can create a pdf generator, either based on an existing web application, or from a special web app only available from the back-end which will be loaded by Puppeteer!

I hope this post was useful to you, see you soon on the blog !

Support the blog

This blog is completely ad-free and if you want to support my work, feel free to donate a dollar !


About the author

Hi, I am Nicolas Brondin-Bernard, freelance web engineer since 2015 with a passion for sharing knownledge and experiences.

I'm also a coach for junior web developers, you can message me on nicolas@brondin.com, on my website or follow me on social networks like Twitter to avoid missing the bests posts or my future projects!


Photo par Hamed Daram sur Unsplash