Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React print not working when hosted on vercel #13

Open
EbubeEvan opened this issue Mar 27, 2024 · 9 comments
Open

React print not working when hosted on vercel #13

EbubeEvan opened this issue Mar 27, 2024 · 9 comments
Assignees
Labels
bug Something isn't working external

Comments

@EbubeEvan
Copy link

When I hosted my Nextjs 14 website on vercel, I was generating the pdf on a server component using tailwincss in the pdf template component.

It worked well on my computer but was throwing errors when hosted. I then changed it to generate on the backend using a route handler and I got an error saying that a particular tailwindcss module couldn't be found.

I changed the styling to plain CSS and I got a status 500 error. All this time, it worked perfectly on my computer so I wonder why it doesn't work when hosted on vercel.

@Titou325
Copy link
Member

Hey @EbubeEvan, could you confirm what version of react-print-pdf you are using? There have been improvements to running Tailwind server-side in the latest versions.

@Titou325 Titou325 added the bug Something isn't working label Mar 27, 2024
@EbubeEvan
Copy link
Author

Hi @Titou325 I'm not sure as I had already uninstalled it before raising the issue. But I know it was the latest version as of March 10th when I installed it.

@thebiltheory
Copy link

thebiltheory commented May 5, 2024

Hey @Titou325,

I will make an assumption here, but it might be related to the fact that Vercel runs on Lambdas.
Puppeteer relies on Chromium, which is way to large to run on Lambdas, but by using @sparticuz/chromium and puppeteer-core on production it will run smoothly.

I created a server action, but can also perfectly run on a route handler.

"use server";

import { Browser } from "puppeteer-core";

export async function makePDF(html) {
  let browser: Browser | undefined | null;

  if (process.env.NODE_ENV !== "development") {
    const chromium = require("@sparticuz/chromium");
    const puppeteer = require("puppeteer-core");

    browser = await puppeteer.launch({
      executablePath: await chromium.executablePath(),
      headless: chromium.headless,
      ignoreHTTPSErrors: true,
      defaultViewport: chromium.defaultViewport,
      args: [...chromium.args, "--hide-scrollbars", "--disable-web-security"],
    });
  } else {
    const puppeteer = require("puppeteer");
    browser = await puppeteer.launch({
      headless: "new",
    });
  }

  if (browser) {
    const page = await browser.newPage();
    await page.setContent(html);

    const pdfBuffer = await page.pdf({
      format: "a4",
      printBackground: true,
      margin: {
        top: 80,
        bottom: 80,
        left: 80,
        right: 80,
      },
    });

    await browser.close();

    return pdfBuffer;
  }

  return null;
}

Route handler:

import { compile } from "@onedoc/react-print";
import { PdfCv } from "../_components/pdf-cv";
import { makePDF } from "../actions/make-pdf";

export async function GET(request: Request) {
  try {
    const headers = new Headers();

    const html = await compile(<PdfCv />);
    const pdfBuffer = await makePDF(html);

    headers.append("Content-Type", "application/pdf");
    headers.append(
      "Content-Disposition",
      `attachment; filename="resume-${new Date().getFullYear()}.pdf"`
    );

    return new Response(pdfBuffer, { headers });
  } catch (error) {
    return new Response("Error downloading PDF", {
      status: 500,
      headers: {
        "Content-Type": "text/plain",
      },
    });
  }
}

You will also need to update your next.config.js file with the following.

experimental: {
    serverComponentsExternalPackages: ["puppeteer-core", "@sparticuz/chromium"],
  },

@Titou325
Copy link
Member

Titou325 commented May 5, 2024

Hey @thebiltheory, thanks for these detailed examples! If using Onedoc as a backend, you don't actually need to run puppeteer as the payload is sent externally for rendering.

This issue originally came from our component that relied on the base Tailwind library, however Tailwind requires a full fledged file system to process just-in-time compilation. We switched to an earlier version of Tailwind patched for JIT a few weeks back to solve this issue, and haven't been able to reproduce it since. However, since there have been occasional reports I kept the thread open!

There is another consideration when running on Vercel regarding the functions timeout as PDF rendering can be slow, sometimes exceeding the default invocation time of 15s. This timeout can be changed for paid customers, and we are releasing speed improvements regularly.

Thanks!

@thebiltheory
Copy link

@Titou325 this is only if you use react-print to put the PDF together.
I personally don't use Onedoc to render the PDF, also the Error 500 on Vercel doesn't say much, so I'm just assuming this could be one of the reasons if you only use react-print on the frontend.

@Titou325
Copy link
Member

Titou325 commented May 5, 2024

Makes sense, do you still use the tailwind component or has it been switched to plain css as well?

@thebiltheory
Copy link

@Titou325, I use tailwind yes, also I believe Onedoc compiles everything to css?

I'm not even sure I need Tailwind. Will check.

@EbubeEvan
Copy link
Author

I had to switch to react-to-print to download pdfs. which was a bummer cos I then had to display the document on the DOM which I didn't want. I also couldn't generate a pdf link to send via email. I really wish react print worked for me.

@Titou325
Copy link
Member

Note that the latest versions of react-print do work on Vercel, with the main caveat being that RSC (use client/use server) cannot be used. This is easy with the pages router, however with the app router, RSC is the default pattern. A common workaround is to expose 2 routes, one with the page and the other one with the call to Fileforge.

The API route calls the Page route to get the rendered HTML from React, and this is passed.

While non-ideal, this is currently hard to bypass as Next monkey patches React's rendering functions.

An issue is open with Next at vercel/next.js#68150

@Titou325 Titou325 self-assigned this Aug 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working external
Projects
None yet
Development

No branches or pull requests

3 participants