I have an API written with Node.js hosted on Heroku and my frontend app is written in Vue.js, it is on Hostinger. I would like to know if is it possible to generate a PDF file with Puppeteer and send it immediately to frontend client without saving it to the disk first? If yes, could you give me some example on how to do it?
Currently my function is like that:
exports.gerarPDFAvaliacao = async (dadosAvaliacao) => {
try {
const compile = async (fileName, data) => {
const filePath = path.join(process.cwd(), 'src/templates/client/operation/', `${fileName}.hbs`);
const html = await fs.readFile(filePath, 'utf-8');
return await hbs.compile(html)(data);
}
const browser = await puppeteer.launch();
const page = await browser.newPage();
let content = await compile('avaliations', dadosAvaliacao);
await page.goto(`data:text/html,${content}`, { waitUntil: 'networkidle0' });
await page.emulateMedia('screen');
await page.pdf({
path: 'src/dist/pdf/' + dadosAvaliacao.arquivo + '.pdf',
format: 'A4',
printBackground: true
})
await browser.close();
return dadosAvaliacao.arquivo + '.pdf';
} catch (error) {
console.log('Errors => ', error);
}
};
According to official documentation, if you do not provide a path the file will not be saved to disk.
page.pdf(options) : Options object which might have the following properties: path The file path to save the PDF to. If path is a relative path, then it is resolved relative to current working directory. If no path is provided, the PDF won't be saved to the disk.
This mean that it should return something like a buffer or a binary representation of the generated file. You just need to return that or pipe that to the response,depending on the framework you are using.
This just outputs the pdf to console:
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
console.log(await page.content());
const pdf = await page.pdf();
await browser.close();
console.log(pdf) // maybe do response(pdf).type('x-pdf')
EDIT: Here is a complete example using express and puppeteer that returns the pdf content directly in-memory. It runs on runkit, so I think the same limitations apply (maybe even more). If you navigate to the public endpoint that the example has you can see how the browser detects that it is a pdf file and renders it properly.
code
const puppeteer = require ('puppeteer');
const express = require('express');
var app = express(exports);
const browser = await puppeteer.launch();
const main = async () => {
const page = await browser.newPage();
await page.goto('https://example.com');
const pdf = await page.pdf();
return pdf;
}
app.get('/', async function (req, res) {
const pdf = await main();
res.contentType("application/pdf");
res.send(pdf);
});
app.listen(3000, function(){ console.log('Listening on 3000') });