puppeteer can't find the helpers of nodejs handlebars

65 Views Asked by At

I'm creating a PDF file using puppeteer in NodeJs. I render the template with handlebars and through the complication I pass the variables so that handlebars get them.

The following code is the one I currently have:

  const browser = await puppeteer.launch({
    headless: 'new',
    // `headless: true` (default) enables old Headless;
    // `headless: 'new'` enables new Headless;
    // `headless: false` enables “headful” mode.
  });
  const page = await browser.newPage();

  // Compila la plantilla Handlebars
  const compiledTemplate = handlebars.compile(template);

  // Renderiza la plantilla Handlebars con los datos necesarios
  const html = compiledTemplate({ datos: datos });

  await page.goto('data:text/html,' + encodeURIComponent(html), { waitUntil: 'networkidle0' });

  // Agrega el archivo JavaScript al contexto de la página web
  await page.addScriptTag({ path: __dirname + '/../public/js/plotly-2.20.0.min.js' });
  await page.addScriptTag({ path: __dirname + '/../public/js/GRAPH/PDF/' + nameFilePPV_L + '.js' });
  await page.addScriptTag({ path: __dirname + '/../public/js/GRAPH/PDF/' + nameFilePPV_T + '.js' });
  await page.addScriptTag({ path: __dirname + '/../public/js/GRAPH/PDF/' + nameFilePPV_V + '.js' });
  await page.addScriptTag({ path: __dirname + '/../public/js/GRAPH/PDF/' + nameFileVSUM + '.js' });

  if (SwitchPPV_L === "on") {
    console.log("SwitchPPV_L: " + SwitchPPV_L)
    await page.evaluate(() => {
      setGrafico_ppv_l();
    });
  }

  if (SwitchPPV_T === "on") {
    console.log("SwitchPPV_T: " + SwitchPPV_T)
    await page.evaluate(() => {
      setGrafico_ppv_t();
    });
  }

  if (SwitchPPV_V === "on") {
    console.log("SwitchPPV_V: " + SwitchPPV_V)
    await page.evaluate(() => {
      setGrafico_ppv_v();
    });
  }
  
  if (SwitchVSUMALL === "on") {
    console.log("SwitchVSUMALL: " + SwitchVSUMALL)
    await page.evaluate(() => {
      setGrafico_vsum();
    });
  }

  const pdf = await page.pdf({ format: 'A5', printBackground: true });

  await browser.close();
  fs.promises.unlink(__dirname + '/../public/js/GRAPH/PDF/' + nameFilePPV_L + '.js')
  fs.promises.unlink(__dirname + '/../public/js/GRAPH/PDF/' + nameFilePPV_T + '.js')
  fs.promises.unlink(__dirname + '/../public/js/GRAPH/PDF/' + nameFilePPV_V + '.js')
  fs.promises.unlink(__dirname + '/../public/js/GRAPH/PDF/' + nameFileVSUM + '.js')
  res.contentType('application/pdf');
  res.send(pdf);

The code works, but when I add a conditional in my hbs template, the code throws the following error which indicates that it can't find the defined helper. How can I access the helpers so that puppeteer can render the hbs template correctly?

Handlebars template

{{#if (test datos.SwitchPPV_L)}}
    <h1>True SwitchPPV_L</h1>
{{else}}
    <h1>False</h1>
{{/if}}

Helper Test

helpers.test = (SwitchPPV_L) => {
    if (SwitchPPV_L === "on") {
        return true
    }else{
        return false
    }
}

LOG:

Error: Missing helper: "test"
1

There are 1 best solutions below

0
On

I can't run your example code since it's not complete (there are a number of undefined variables) but here's a fully runnable example you can hopefully convert to your use case. Specifically, it registers the test helper with Handlebars to avoid the "Missing helper" error.

const datos = {SwitchPPV_L: "on"};
Handlebars.registerHelper("test", SwitchPPV_L => SwitchPPV_L === "on");
const html = document.querySelector("#template").innerHTML;
const template = Handlebars.compile(html);
document.body.innerHTML = template({datos});
<script id="template" type="text/x-handlebars-template">
{{#if (test datos.SwitchPPV_L)}}
    <h1>True SwitchPPV_L</h1>
{{else}}
    <h1>False</h1>
{{/if}}
</script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/handlebars.js"></script>

With Puppeteer and Express:

const express = require("express"); // ^14.18.2
const Handlebars = require("handlebars"); // ^4.7.8
const puppeteer = require("puppeteer"); // ^21.4.1

const html = `{{#if (test datos.SwitchPPV_L)}}
    <h1>True SwitchPPV_L</h1>
{{else}}
    <h1>False</h1>
{{/if}}`;
Handlebars.registerHelper("test", SwitchPPV_L => SwitchPPV_L === "on");
const template = Handlebars.compile(html);

const app = express();
app.set("port", process.env.PORT || 3001)
app.get("/", async (req, res) => {
  let browser;

  try {
    browser = await puppeteer.launch({headless: "new"});
    const [page] = await browser.pages();
    const datos = {SwitchPPV_L: "on"};
    await page.setContent(template({datos}));
    const pdf = await page.pdf();
    res.contentType("application/pdf");

    // optionally:
    res.setHeader(
      "Content-Disposition",
      "attachment; filename=test.pdf"
    );

    res.send(pdf);
  }
  catch (err) {
    console.error(err);
    res.sendStatus(500);
  }
  finally {
    await browser?.close();
  }
});
app.listen(
  app.get("port"),
  () => console.log(`running on ${app.get("port")}`)
);

To test, run node index.js and navigate to http://localhost:3001 to observe the PDF. Once you have that working, it's a matter of making the variables dynamic and running whatever functions you want before snapping the PDF.

Once you have your code working, you may consider sharing a browser across requests as shown here.