Q:

Use Puppeteer to Generate a PDF on Client Side

I'm struggling to get Puppeteer to download a file within the browser. I currently have it saving the file locally on Cloud9, but I want to click a download PDF button and have it download in Chrome.
I've tried saving the page.pdf to a variable and that hasn't worked. I've also tried opening the locally saved file, but I can't get that to work either. 
var express = require("express");
var puppeteer = require("puppeteer");

module.exports = function pdf(url, req) {(async () => {
      var browser = await puppeteer.launch();
      var page = await browser.newPage();
      await page.goto('https://node-and-mysql-mbegg.c9users.io/clients/'+req.params.id+'/reports/monthlyreport/'+req.params.marketplace+'/'+req.params.month, {waitUntil: 'networkidle2'});
      await page.pdf({path: 'public/temp/Performance Report -'+req.params.month+'.pdf', format: 'A4', landscape: true, printBackground: true});

      await browser.close();
    })();
}

///Print PDF route
router.get("/clients/:id/reports/monthlyreport/:marketplace/:month/pdf", function(req, res) {
    var url = "/clients/"+req.params.id+"/reports/monthlyreport/"+req.params.marketplace+"/"+req.params.month
    pdf(url, req);
    res.contentType("application/pdf");
    res.send(pdf);;
});

I know that the res.send(pdf) requires the page.pdf() to be saved to a variable and returned. I just didn't remove that from the route.
What happens when I save page.pdf() to a variable is I just get a blank file - not PDF - and it appears just to be a blank buffer or something. I don't know what I'm doing wrong to not get the file downloading in the chrome browser.

A:

While within the pdf function you seem to be waiting for each of the puppeteer operations, you are actually not waiting for the call to pdf function in your express route. Additionally, the pdf function right now doesn't return anything! You would need to make following modifications to your program: 

The pdf function should return the filename to which the generated PDF was saved. While you are at it might as well get rid of the IIFE, its not required, simply declare the outer function as async.
In the route function, program should wait for the filename to be returned form the pdf(...) call. This can done by using Promise, or await. If await is preferred, the outer function should be marked as async.
The sendFile function provided by express on response objects should be used to send the generated PDF file to client. Please note that res.sendFile expects the absolute path to the file.

Following is a modified version of your program which implements these.
const express = require("express");
const puppeteer = require("puppeteer");
const path = require('path');

module.exports = async function pdf(url, req) {
    const filename = `public/temp/Performance Report -${req.params.month}.pdf`;
    const browser = await puppeteer.launch();
    const page = await browser.newPage();

    await page.goto('https://node-and-mysql-mbegg.c9users.io/clients/'+req.params.id+'/reports/monthlyreport/'+req.params.marketplace+'/'+req.params.month, {waitUntil: 'networkidle2'});
    await page.pdf({path: filename, format: 'A4', landscape: true, printBackground: true});

    await browser.close();
    return filename;
}

///Print PDF route
router.get("/clients/:id/reports/monthlyreport/:marketplace/:month/pdf", async function(req, res) {
    var url = "/clients/"+req.params.id+"/reports/monthlyreport/"+req.params.marketplace+"/"+req.params.month

    const filename = await pdf(url, req);
    res.contentType("application/pdf");
    res.sendFile(path.join(__dirname, filename)); // if 'public/temp/...' path is not relative to cur dir, make relevant change here.
});

