'Generate 1000 pdf with survey pdf

I'm trying to generate more than one thousand pdf files using surveyPDF.

The problem is that i can generate only 80 pdf files...

I'm passing an array with more than 1000 pdf to generate.

Code :

   query.map(async items => {
      const { generatePdf } = await import("~/lib/survey");
      const filename = kebabCase(
        `${campaign.title} - ${items.employee.fullName.toLowerCase()} -${moment().format("DD/MM/YYYY - HH:mm")} `
      );
      return generatePdf(campaign.template.body, items, filename, 210, 297);
    });

The code which generate each pdfs :

import autoTable from "jspdf-autotable";
import { SurveyPDF, CommentBrick, CompositeBrick, PdfBrick, TextBrick } from "survey-pdf";
import { format } from "~/utils/date";

class AutoTableBrick extends PdfBrick {
  constructor(question, controller, rect, options) {
    super(question, controller, rect);
    this.margins = {
      top: controller.margins.top,
      bottom: controller.margins.bot,
      right: 30,
      left: 30,
    };
    this.options = options;
  }
  renderInteractive() {
    if (this.controller.doc.lastAutoTable && !this.options.isFirstQuestion) {
      this.options.startY = this.yTop;
    }
    autoTable(this.controller.doc, {
      head: [
        [
          {
            content: this.question.title,
            colSpan: 2,
            styles: { fillColor: "#5b9bd5" },
          },
        ],
      ],
      margin: { ...this.margins },
      styles: { fillColor: "#fff", lineWidth: 1, lineColor: "#5b9bd5", minCellWidth: 190 },
      alternateRowStyles: { fillColor: "#bdd6ee" },
      ...this.options,
    });
  }
}

export async function generatePdf(json, data, filename, pdfWidth, pdfHeight) {
  if (!json) {
    return Promise.reject("Invalid json for pdf export");
  }
  for (const page of json.pages) {
    page.readOnly = true;
  }
  const surveyPDF = new SurveyPDF(json, {
    fontSize: 11,
    format: [pdfWidth, pdfHeight],
    commercial: true,
    textFieldRenderAs: "multiLine",
  });
  surveyPDF.showQuestionNumbers = "off";
  surveyPDF.storeOthersAsComment = false;
  //TODO This does not work well with dynamic dropdown, bug declared
  // surveyPDF.mode = "display";
  surveyPDF.mergeData({ ...data, _: {} });

  surveyPDF.onRenderQuestion.add(function(survey, options) {
    const { bricks, question } = options;

    if (question.getType() === "comment" && question.value && bricks.length > 0) {
      for (const brick of bricks) {
        if (brick.value) {
          brick.value = question.value.replace(/\t/g, "  ");
        }
        if (brick instanceof CompositeBrick) {
          const { bricks } = brick;
          for (const brick of bricks) {
            if (brick instanceof CommentBrick) {
              brick.value = question.value.replace(/\t/g, "  ");
            }
          }
        }
      }
    }
  });

  surveyPDF.onRenderQuestion.add(async function(survey, options) {
    const {
      point,
      bricks,
      question,
      controller,
      module: { SurveyHelper },
    } = options;

    if (question.getType() === "multipletext") {
      const body = [];
      let extraRows = 0;
      let rows = question.getRows();
      for (let i = 0; i < rows.length; i++) {
        for (let j = 0; j < rows[i].length; j++) {
          let { title, value, inputType } = rows[i][j];
          if (inputType === "date") {
            value = format(value);
          }
          if (typeof value === "string" && value.length > 0) {
            const valueEstRows = value.match(/.{1,70}/g).length;
            if (valueEstRows > 1) {
              extraRows += valueEstRows;
            }
          }
          body.push([title, value || "N/A"]);
        }
      }
      //TODO Use SurveyHelper helperDoc do calculate the height of the auto table
      const startY = point.yTop;
      const height = 21.5 * (body.length + 1) + 8.5 * extraRows;
      const isFirstQuestion = question.title === question.parent.questions[0].title;
      options.bricks = [
        new AutoTableBrick(question, controller, SurveyHelper.createRect(point, bricks[0].width, height), {
          startY,
          body,
          isFirstQuestion,
        }),
      ];
    }
  });

  surveyPDF.onRenderQuestion.add(async function(survey, options) {
    const {
      point,
      question,
      controller,
      module: { SurveyHelper },
    } = options;

    if (question.getType() === "text") {
      //Draw question background
      const { default: backImage } = await import("~/public/assets/images/block.png");
      const backWidth = SurveyHelper.getPageAvailableWidth(controller);
      const backHeight = SurveyHelper.pxToPt(100);
      const imageBackBrick = SurveyHelper.createImageFlat(point, null, controller, backImage, backWidth, backHeight);

      options.bricks = [imageBackBrick];

      point.xLeft += controller.unitWidth;
      point.yTop += controller.unitHeight;
      const oldFontSize = controller.fontSize;
      const titleBrick = await SurveyHelper.createTitleFlat(point, question, controller);
      controller.fontSize = oldFontSize;
      titleBrick.unfold()[0]["textColor"] = "#6a6772";

      options.bricks.push(titleBrick);

      //Draw text question text field border
      let { default: textFieldImage } = await import("~/public/assets/images/input.png");
      let textFieldPoint = SurveyHelper.createPoint(imageBackBrick);
      textFieldPoint.xLeft += controller.unitWidth;
      textFieldPoint.yTop -= controller.unitHeight * 3.3;
      let textFieldWidth = imageBackBrick.width - controller.unitWidth * 2;
      let textFieldHeight = controller.unitHeight * 2;
      let imageTextFieldBrick = SurveyHelper.createImageFlat(
        textFieldPoint,
        null,
        controller,
        textFieldImage,
        textFieldWidth,
        textFieldHeight
      );

      options.bricks.push(imageTextFieldBrick);

      textFieldPoint.xLeft += controller.unitWidth / 2;
      textFieldPoint.yTop += controller.unitHeight / 2;
      let textFieldValue = question.value || "";
      if (textFieldValue.length > 90) {
        textFieldValue = textFieldValue.substring(0, 95) + "...";
      }
      const textFieldBrick = await SurveyHelper.createBoldTextFlat(
        textFieldPoint,
        question,
        controller,
        textFieldValue
      );
      controller.fontSize = oldFontSize;
      textFieldBrick.unfold()[0]["textColor"] = "#EFF8FF";

      options.bricks.push(textFieldBrick);
    }
  });

  surveyPDF.onRenderQuestion.add(async function(survey, options) {
    const {
      point,
      question,
      controller,
      module: { SurveyHelper },
    } = options;

    if (question.getType() === "radiogroup" || question.getType() === "rating") {
      options.bricks = [];

      const oldFontSize = controller.fontSize;
      const titleLocation = question.hasTitle ? question.getTitleLocation() : "hidden";
      let fieldPoint;
      if (["hidden", "matrix"].includes(titleLocation)) {
        fieldPoint = SurveyHelper.clone(point);
      } else {
        const titleBrick = await SurveyHelper.createTitleFlat(point, question, controller);
        titleBrick.xLeft += controller.unitWidth;
        titleBrick.yTop += controller.unitHeight * 2;
        controller.fontSize = oldFontSize;
        titleBrick.unfold()[0]["textColor"] = "#6a6772";

        options.bricks.push(titleBrick);

        fieldPoint = SurveyHelper.createPoint(titleBrick);
        fieldPoint.yTop += controller.unitHeight * 1.3;
      }

      //Draw checkbox question items field
      const { default: itemEmptyImage } = await import("~/public/assets/images/unchecked.png");
      const { default: itemFilledImage } = await import("~/public/assets/images/checked.png");
      const itemSide = controller.unitWidth;
      let imageItemBrick;
      const choices = question.getType() === "rating" ? question.visibleRateValues : question.visibleChoices;
      for (const choice of choices) {
        const isItemSelected =
          question.getType() === "rating" ? question.value === choice.value : choice === question.selectedItem;

        imageItemBrick = SurveyHelper.createImageFlat(
          fieldPoint,
          null,
          controller,
          isItemSelected ? itemFilledImage : itemEmptyImage,
          itemSide,
          itemSide
        );

        options.bricks.push(imageItemBrick);

        const textPoint = SurveyHelper.clone(fieldPoint);
        textPoint.xLeft += itemSide + controller.unitWidth / 2;
        textPoint.yTop += itemSide / 12;
        const itemValue = choice.locText.renderedHtml;
        const checkboxTextBrick = await SurveyHelper.createTextFlat(
          textPoint,
          question,
          controller,
          itemValue,
          TextBrick
        );
        checkboxTextBrick.unfold()[0]["textColor"] = "#6a6772";
        fieldPoint.yTop = imageItemBrick.yBot + SurveyHelper.GAP_BETWEEN_ROWS * controller.unitHeight;

        options.bricks.push(checkboxTextBrick);
      }
    }
  });

  surveyPDF.onRenderFooter.add(function(survey, canvas) {
    canvas.drawText({
      text: canvas.pageNumber + "/" + canvas.countPages,
      fontSize: 10,
      horizontalAlign: "right",
      margins: {
        right: 12,
      },
    });
  });

  return await surveyPDF.raw(`./pdf/${filename}.pdf`);
}

The error :

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

I have already try to increase the node memory using $env:NODE_OPTIONS="--max-old-space-size=8192"



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source