Next.js Discord

Discord Forum

Generate PDF on NextJS

Unanswered
Giant Chinchilla posted this in #help-forum
Open in Discord
Avatar
Giant ChinchillaOP
Hi ,
I want to generate PDF on NextJS from React template

I looked at different tools ...
react-pdf, pdfkit, wkhtmltopdf, html2pdf ...

Nothing work for me, I don't understand when I need to use server actions or client context, my app running on vercel, and I want to save my files on Vercel Blob or AWS S3
The only thing that works it's @fileforge/react-print to generate my PDF but it's deprecated 😅

Does anyone have a solution for me with a working example using nextjs?

Thanks

#nextjs #html #pdf

17 Replies

Avatar
Pygmy Nuthatch
They all use puppeteer
So use a templating language and pupetter
Is is slow af
3000ms
Minumum
I wrote ot on rust and there it was about 2000ms at 25 concurent users
@Giant Chinchilla
Avatar
Giant ChinchillaOP
OK , i've tried
export const POST = async (req: NextRequest) => {
  const body = await req.json();
  const browser = await puppeteer.launch()
  const page = await browser.newPage()

  const html = body?.html || '<h1>Hello, World!</h1>'
  await page.setContent(html, { waitUntil: 'domcontentloaded' });

  const pdfBuffer = await page.pdf({ format: 'A4',  path: 'result.pdf', })
  await browser.close()


But I want to generate HTML template with React Templating system
Avatar
Giant ChinchillaOP
And I don't know what to do with my pdfBuffer variable, so that I can return it to my calling component to open the PDF in a new tab.
Avatar
Giant ChinchillaOP
OK my solution

// component
"use client";

import type { ComponentPropsWithoutRef } from "react";
import { compile } from "@fileforge/react-print";
import { Document } from "../../../documents/Document";

export type GenerateDocProps = ComponentPropsWithoutRef<"div"> & {};

export const GenerateDoc = ({
  children,
  className,
  ...props
}: GenerateDocProps) => {
  return (
    <button
      onClick={async () => {
        const html = await compile(<Document />);

        fetch("/api/pdf", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ html }),
        }).then(async (res) => {
          const { pdfUrl } = await res.json();
          window.open(pdfUrl);
        });
      }}
    >
      test
    </button>
  );
};`


And my API route
// /api/pdf/route.ts
import { put } from '@vercel/blob';
import { NextRequest, NextResponse } from 'next/server';
import puppeteer from 'puppeteer'

export const POST = async (req: NextRequest) => {
  const body = await req.json();
  const browser = await puppeteer.launch()
  const page = await browser.newPage()

  const html = body?.html || '<h1>Hello, World!</h1>'
  await page.setContent(html, { waitUntil: 'domcontentloaded' });

  const pdfBuffer = await page.pdf({ format: 'A4'})
  await browser.close()

  const { url } = await put(`generated-${Date.now()}.pdf`, pdfBuffer, {
    access: 'public',
    contentType: 'application/pdf',
  });

  return NextResponse.json({
    ok: true,
    pdfUrl: url,
  });

}


If someone have an alternative to import { compile } from "@fileforge/react-print"; for client side
Maybe https://react-pdf.org/ but I have an error for no-node API if when I generate my file
Avatar
Giant ChinchillaOP
..Puppeteer doesn't work on Vercel 😢
Avatar
Pygmy Nuthatch
Yea sorry i localhost so use like a aws lambda or something and write it i. Rust or go while you are at it
Avatar
If I were you, I'd create a separate function in AWS Lambda for it, and call it via fetch api
Avatar
@Giant Chinchilla Resolved?
Avatar
Asiatic Lion
SAME PROBLEM ANY SOLUTION??
Avatar
Pygmy Nuthatch
Yes use a lambda function for it and fetch it
Avatar
Korat