Create PDF in Firebase Cloud Functions

I worked on this too and here below you can find a sample of cloud function that is creating a PDF file from a template HTML hosted on firebase storage. It uses Hanldebars to apply some data to the template and then upload it again on firebase storage. I used node-html-pdf here.

const functions = require('firebase-functions');
const admin = require('firebase-admin');
const pdf = require('html-pdf');
const gcs = require('@google-cloud/storage')({
  projectId: '[YOUR PROJECT ID]',
  //key generated from here https://console.firebase.google.com/project/_/settings/serviceaccounts/adminsdk?authuser=1
  keyFilename: '[YOUR KEY]'
});
const handlebars = require('handlebars');
const path = require('path');
const os = require('os');
const fs = require('fs');
const bucket = gcs.bucket('[YOUR PROJECT ID].appspot.com');

admin.initializeApp(functions.config().firebase);

exports.helloWorld = functions.https.onRequest((request, response) => {
  // data to apply to template file
  const user = {
    "date": new Date().toISOString(),
    "firstname" : "Guillaume",
  };
  const options = {
    "format": 'A4',
    "orientation": "portrait"
  };
  const localTemplate = path.join(os.tmpdir(), 'localTemplate.html');
  const localPDFFile = path.join(os.tmpdir(), 'localPDFFile.pdf');

  bucket.file('template.html').download({ destination: localTemplate }).then(() => {
    console.log("template downloaded locally");
    const source = fs.readFileSync(localTemplate, 'utf8');
    const html = handlebars.compile(source)(user);
    console.log("template compiled with user data", html);

    pdf.create(html, options).toFile(localPDFFile, function(err, res) {
      if (err){
        console.log(err);
        return response.send("PDF creation error");
      }
      console.log("pdf created locally");

      return bucket.upload(localPDFFile, { destination: user.name + '.pdf', metadata: { contentType: 'application/pdf'}}).then(() => {
        response.send("PDF created and uploaded!");
      }).catch(error => {
        console.error(error);
        response.send("PDF created and uploaded!");
      });
  });
  });
});

Hope this will help the next one doing this :)


I tried Guillaume's suggestion and it ALMOST got me there. Unfortunately, Phantomjs was exiting without finishing.

I ended up solving this by combining Guillaume's solution and https://phantomjscloud.com (and their library.) Now it's all working like a charm.

After "template compiled with user data", substitute the following:

 const phantomJsCloud = require("phantomjscloud");
 const browser = new phantomJsCloud.BrowserApi([YOURPHANTOMJSCLOUDAPIKEY]);

 var pageRequest = { content: html, renderType: "pdf" }; 

 // Send our HTML to PhantomJS to convert to PDF

 return browser.requestSingle(pageRequest)
      .then(function (userResponse) {
          if (userResponse.statusCode != 200) {
               console.log("invalid status code" + userResponse.statusCode);
            } else {
               console.log('Successfully generated PDF');

               // Save the PDF locally
               fs.writeFile(localPDFFile, userResponse.content.data, {
                           encoding: userResponse.content.encoding,
                       }, function (err) {                             
                           // Upload the file to our cloud bucket
                           return pdfBucket.upload(localPDFFile, { destination: 'desired-filename.pdf', metadata: { contentType: 'application/pdf'}}).then(() => {
                             console.log('bucket upload complete: '+ localPDFFile);
                           }).catch(error => {
                             console.error('bucket upload error:', error);
                           });
                       });

                   }

                   });

A little bit late.

https://edgecoders.com/generating-a-pdf-with-express-in-node-js-d3ff5107dff1


import * as functions from 'firebase-functions';
import * as PDFDocument from 'pdfkit';

export const yourFunction = functions
  .https
  .onRequest((req,  res) => {
    const doc = new PDFDocument();
    let filename = req.body.filename;
    // Stripping special characters
    filename = encodeURIComponent(filename) + '.pdf';
    // Setting response to 'attachment' (download).
    // If you use 'inline' here it will automatically open the PDF
    res.setHeader('Content-disposition', 'attachment; filename="' + filename + '"');
    res.setHeader('Content-type', 'application/pdf');
    const content = req.body.content;
    doc.y = 300;
    doc.text(content, 50, 50);
    doc.pipe(res);
    doc.end();
  });

hope this can help anyone


Just working on this too, for saving the PDF in the storage it works like this

const myPdfFile = admin.storage().bucket().file('/test/Arbeitsvertrag.pdf');
const doc = new pdfkit();
const stream = doc.pipe(myPdfFile.createWriteStream());
doc.fontSize(25).text('Test 4 PDF!', 100, 100);
doc.end();

return res.status(200).send();

Guess you should wait until the stream is closed and listen for Errors and Things, but this is the first working example I was able to make, now working on how to get a Image from the storage into the PDF.