-
-
Notifications
You must be signed in to change notification settings - Fork 908
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
Next.js and v9 on build Promise.withResolvers #1811
Comments
downgrading to 8.0.2 solved the issue |
Also seeing this issue on Next 14 during the build process. 8.0.2 has a high security vulnerability due to referencing pdfjs-dist@3.11.174, so it's not a great workaround. |
This comment was marked as spam.
This comment was marked as spam.
I was able to resolve the issue by setting the dynamic component to load without server-side rendering (SSR). and make sure in next.config.js enable this |
Which version of Next/React-PDF are you using? Would you be able to paste your full component please? |
All, and see updated upgrade guide for workarounds: |
@wojtekmaj - I think the upgrade guide should read: |
Regarding the workarounds... I'm unsure how to use the polyfill for Promise.withResolvers. Is there a guide somewhere on how to do this for react-pdf? |
I'm also experiencing this on Remix Edit: It seems that the error is coming from within the worker itself, making this difficult to polyfill. I have tried to place a polyfill both in the root as well as in the client component where I have included the worker, but neither worked for me. |
Perhaps using a legacy worker would help? 🤔 |
I tried using a legacy worker, but sadly that did not help. That being said, the following polyfill worked like a charm:
Once I added this, it worked fantastically! 😁 |
I referred to this commit and used a polyfill from core-js. As a result, I was able to make it work. If core-js is available, this method might also work.
|
@justinfarrelldev Where did you add this specifically? I assumed adding to entry.client would be the place, but that didn't resolve it for me. |
Sorry, I could have been more clear - I put this snippet in the component where the Document and Page tags are (IE, the component used to show the PDF - I called it pdfViewer.client.tsx). For more context, I also imported the TextLayer.css and AnnotationLayer.css within this file (at the top, as imports) as well as the worker src. Basically, almost all react-pdf logic is isolated within this client component. I'll post the source code shortly (and edit this comment when I do). Edit:
|
The issue is still present. After running the example app I'm getting error in the console Using the proposed polyfills doesn't seem to solve it. |
Try adding an "else" to the polyfill I posted above and then using "global" instead of window within that else statement. That should help to handle SSR |
if (typeof Promise.withResolvers === "undefined") {
if (window) {
// @ts-expect-error This does not exist outside of polyfill which this is doing
window.Promise.withResolvers = function () {
let resolve, reject
const promise = new Promise((res, rej) => {
resolve = res
reject = rej
})
return { promise, resolve, reject }
}
} else {
// @ts-expect-error This does not exist outside of polyfill which this is doing
global.Promise.withResolvers = function () {
let resolve, reject
const promise = new Promise((res, rej) => {
resolve = res
reject = rej
})
return { promise, resolve, reject }
}
}
} Nothing changes, the same error occurs. I also tried 2ba89d8 with the same result |
Thank you, It works for me with the same configuration. |
Any update on this?, none of above worked for me |
Loading a Polyfill and putting Here's the code I used: import 'core-js/full/promise/with-resolvers.js';
// Polyfill for environments where window is not available (e.g., server-side rendering)
if (typeof Promise.withResolvers === 'undefined') {
if (typeof window !== 'undefined') {
window.Promise.withResolvers = function () {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
};
} else {
global.Promise.withResolvers = function () {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
};
}
} |
Updated to latest one 9.1.0 and now getting this error, downgraded and still same :| |
Super hacky, but this is how we added the polyfill to the pdfjs worker itself, in function transformPdfJsWorker(): Plugin {
return {
name: 'transform-pdf-js-worker',
generateBundle(options, bundle) {
for (const [fileName, chunkOrAsset] of Object.entries(bundle)) {
if (!fileName.includes('pdf.worker') || chunkOrAsset.type !== 'asset') {
continue
}
const prepend = Buffer.from(
`if (typeof Promise.withResolvers === "undefined") {
Promise.withResolvers = function () {
let resolve, reject
const promise = new Promise((res, rej) => {
resolve = res
reject = rej
})
return { promise, resolve, reject }
}
}
`,
'utf-8'
)
const sourceBuffer = Buffer.isBuffer(chunkOrAsset.source)
? chunkOrAsset.source
: Buffer.from(chunkOrAsset.source)
chunkOrAsset.source = Buffer.concat([prepend, sourceBuffer])
}
},
}
}
export default defineConfig({
plugins: [
transformPdfJsWorker(),
],
}) |
This works for me if I put the polyfill in _app.tsx. It works in both local and production. |
For anyone still struggling with this. Don't bother loading polyfills yourself, it will not work. You have to load the Legacy version of PdjJS worker which is already polyfilled. See https://github.com/mozilla/pdf.js/wiki/Frequently-Asked-Questions#faq-support Like so: import { pdfjs } from "react-pdf";
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/legacy/build/pdf.worker.min.mjs',
import.meta.url,
).toString(); |
Okay, so after a few tests, you still have to polyfill Promise.withResolvers because react-pdf uses non-legacy pdf.mjs even if you choose the legacy pdf worker. |
Getting the same error:
|
@wojtekmaj Hey, sorry, is there any proper solution for this error? and this Doesnt help. The latest version of Chrome and nextjs 14.2.5 and this error. |
For anyone struggling with remix (v This worked for me: I created a //promisePolyfill.ts
if (typeof Promise.withResolvers !== "function") {
Promise.withResolvers = function <T>() {
let resolve!: (value: T | PromiseLike<T>) => void;
let reject!: (reason?: any) => void;
const promise = new Promise<T>((res, rej) => {
resolve = res;
reject = rej;
});
return { promise, resolve, reject };
};
}
export {}; //yourfile.client.tsx
import "~/utils/promisePolyfill";
import { useCallback, useRef, useState } from "react";
import { useResizeObserver } from "@wojtekmaj/react-hooks";
import { pdfjs, Document, Page } from "react-pdf";
import "react-pdf/dist/esm/Page/AnnotationLayer.css";
import "react-pdf/dist/esm/Page/TextLayer.css";
import { PDFToolbar } from "./pdfToolbar";
import { LoaderCircle } from "lucide-react";
import { IPDFViewerProps } from "~/types/pdfViewerTypes";
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
"/pdf.worker.min.mjs",
import.meta.url,
).toString(); Do make sure that that your file is only rendering on the client side, so rename your file to : Also if you have issues with the typing for the promise polyfill remember to create your global.d.ts for it: interface PromiseConstructor {
withResolvers<T>(): {
promise: Promise<T>;
resolve: (value: T | PromiseLike<T>) => void;
reject: (reason?: any) => void;
};
} |
page.tsx: const PDFViewer = dynamic(
() => import('./pdf-viewer').then(mod => mod.PDFViewer),
{ ssr: false }
) pdf-viewer.tsx "use client"
import { Document, Page, pdfjs } from 'react-pdf'
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.mjs',
import.meta.url
).toString()
export function PDFViewer() {
return (
<Document>
<Page />
</Document>
) |
It fixed my tests execution which was failing since I added react-pdf to my project. I've tried all solutions above nothing worked until I found your solution, thank you! |
@wojtekmaj The issue is still reproducible in some cases The issue is related to pdf.js dependency. |
UPDATE: Solution would be updating conflicting dependancies, especially if you're using Angular |
Worked for me as well. Thanks! |
Just wanted to throw some observations I discovered while testing this, For those still facing this issue while using react + Next JS Pages + Promise.withResolvers bypass If you are planning to host your project on Vercel or any other hosting that doesn't have node 22.x support yet, below is the working solution. @Kasui92 this error occurs because Vercel currently defaults to Node.js 20.x, while My project config uses the below packages:
Here’s a polyfill solution for TypeScript:
Javascript
Now You can call
Now lets use the legacy version of
Finally, lets build it for production to test
Note: This is a working solution that i use on my active projects. It works 100% on vercel and other hostings that doesn't support node 20.x Enjoy XD 💯 |
@Bfaschat Thank you for the comments and the working solution! |
Merci <3 |
Hey everyone :) Make sure you are running Trying to use Node 22.x gives a new error, i didn't have time to debug it so i defaulted back to 20.x I hope my solution above works as expected Happy coding |
This worked for me. |
Excellent!!! It worked for me. |
Thankyouuu soo muchhh you saved me!!! |
This still doesn't work for me when I use Nextjs 14.2.11 :( When I run npm run build I get a craaazy long error with lots of whitespace and this on the bottom: Caused by:
|
add this code to next.config.mjs
|
After many tried so hard with the previous answers and the error still remaning, @armanmasangkay solution works for me just well, thanks a lot bro! |
I had the same mistake, but do it |
This along with this polyfill works for me 🎉
|
TLDR - Next.JS is trying to run client side code, server side but some of that code relies on APIs that don't exist in Node.JS env ( If you want to run the non-legacy pdfjs web worker code from a Next.JS, I found one way to do that with something like this: // So we can at least still get typescript type info,
// import only the types for react-pdf
import type * as reactPdfType from "react-pdf";
// Workaround for https://github.com/wojtekmaj/react-pdf/issues/1811
let reactPdf: typeof reactPdfType | undefined;
if (typeof window !== "undefined") {
reactPdf = require("react-pdf");
}
// URL for the worker file (if you're using the CDN)
// We need to use the CDN link to try and work around
// this issue: https://github.com/vercel/next.js/discussions/61549
if (reactPdf?.pdfjs && typeof window !== "undefined") {
const workerSrc = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${reactPdf.pdfjs.version}/pdf.worker.min.mjs`;
reactPdf.pdfjs.GlobalWorkerOptions.workerSrc = workerSrc;
}
// ...
// Use <reactPdf.Document {/*...*/} />
// ... |
Before you start - checklist
Description
I'm trying to implement the library in a Next.js 14.2.3 (App Router) project without turbopack, however when I go to use the proposed examples it reports the error in the title directly in the console during development or when it's launched the build command.
Having to use Node 20 because Vercel doesn't support 22, I immediately adopted legacy mode to solve the problem... but with poor results.
I also installed
core-js
and imported directly into the layout in root, but although it solves the error during development, it gives me an error when I build the app.Can I ask if I'm missing any steps?
Steps to reproduce
Expected behavior
The build command should work.
Actual behavior
The build command reports an error "failed to parse input file" or "Promise.withResolvers" if core-js is not installed.
Additional information
/src/app/layout.js
/src/app/page.js
/src/app/PdfViewer.js
The example PDF is the same one used in the sample, placed in /public.
Environment
The text was updated successfully, but these errors were encountered: