Search code examples
node.jspdfhummus.js

Mailmerge pdf in nodejs and hummus-recipe


I'm trying to make a simple mail-merge where recipients information is inserted on top of a template pdf.

The template is 1 page, but the result can be up to several hundred pages.

I have all recipient in array objects, but need to find a way to loop over that and create a unique page for each recipient.

I'm not sure if hummus-recipe is the right tool, so would greatly appreciate any input as to how to do this.

My demo looks like this

const HummusRecipe = require('hummus-recipe')

const recepients = [
    {name: "John Doe", address: "My Streetname 23", zip: "23456", city: "My City"}, 
    {name: "Jane Doe", address: "Another Streetname 56 ", zip: "54432", city: "Her City"} 
    //'.......'
]

const template = 'template.pdf';
const pdfDoc = new HummusRecipe(template, 'output.pdf');

function createPdf(){
    pdfDoc
    .editPage(1)
    .text(recepients[0].name, 30, 60)
    .text(recepients[0].address, 30, 75)
    .text(recepients[0].zip + ' ' + recepients[0].city, 30, 90)
    .endPage()

    //. appendpage(template) - tried versions of this in loops etc., but can't get it to work.

    .endPDF();
}

createPdf();

This obviously only create a single page with recipient[0]. I have tried all sorts of ways to loop over using .appendpage(template), but I can't append and then edit the same page.

Any advice how to move forward from here?


Solution

  • After conversing with the creator of hummus-recipe and others, the solution became somewhat obvious. Its not possible to append a page and then modify it, and its not possible to modify the same page several times.

    The solution then is to make the final pdf in two passes. First create a masterPdf where the template is appended in a for loop, save this file and then edit each of those pages.

    I have created a working code as shown below. I have made the functions async as I need to run it on lambda an need som control over returns etc. Also this way its possible to save both the tmp-file and final pdf on AWS S3.

    The code below takes about 60 seconds to create a 200 page pdf from a 1,6mb template. Any ideas for optimizations will be greatly appreciated.

    const HummusRecipe = require('hummus-recipe');
    const template = 'input/input.pdf';
    
    const recipients = [
        {name: 'John Doe', address: "My Streetname 23"}, 
        {name: 'Jane Doe', address: "Another Streetname 44"},
        //...etc.
    ]
    
    async function createMasterPdf(recipientsLength) {
        const key = `${(Date.now()).toString()}.pdf`;
        const filePath = `output/tmp/${key}`;
        const pdfDoc = new HummusRecipe(template, filePath)
    
        for (i = 1; i < recipientsLength; i++) {
            pdfDoc
            .appendPage(template)
            .endPage()
        }
        pdfDoc.endPDF();
        return(filePath)
    
    }
    
    async function editMasterPdf(masterPdf, recipientsLength) {
        const key = `${(Date.now()).toString()}.pdf`;
        const filePath = `output/final/${key}`;
        const pdfDoc = new HummusRecipe(masterPdf, filePath)
    
        for (i = 0; i < recipientsLength; i++) {
            pdfDoc
            .editPage(i+1)
            .text(recipients[i].name, 75, 100)
            .text(recipients[i].address, 75, 115)
            .endPage()
        }
        pdfDoc.endPDF()
        return('Finished file: ' + filePath)
    
    }
    
    
    const run = async () => {
        const masterPdf = await createMasterPdf(recipients.length);
        const editMaster = await editMasterPdf(masterPdf, recipients.length)
        console.log(editMaster)
    }
    
    run()