Open tobiasbueschel opened 6 months ago
This definitely look like a flavor of #1508 and #1620.
You did everything just the way I'd do. I'm puzzled. If importing PdfViewer asynchronously in <BrowserOnly>
doesn't help, maybe it'd be better to ask on Docusaurus repo why that could be the case? I don't see any reason for BrowserOnly to be executed on the server side!
I just had this specific problem with almost the exact same setup. The differences being that as of now, July 27, 2024, I have more recent versions of React-PDF (9.1.0); webpack (5.93.0); and docusaurus(3.4). That being said, I built my client within a docker container, but the issues encountered were all from the build step, or a result of the build.
This solution I imagine should work also for a Next.js app that has static site generation issues (replace lazy with dynamic, and maybe also browserOnly with something else) because the plugin workaround you listed above led me to a solution to the build issue, but created a render issue, which is what the Promise.withResolvers part from the #1508 thread is for. Then, the page rendered correctly and the component could input a pdf to load, but could not load it, which led to the worker import workaround, which led to resize issues, which led to recreating the useResizeObserver hook and then it all finally worked:
npx
for the docusaurus;if (typeof Promise.withResolvers === "undefined") {
if (window) {
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 }
}
}
}
pdfjs.GlobalWorkerOptions.workerSrc = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.mjs`
import React, { lazy, Suspense } from 'react'
const AnyName = lazy(() => import("./PDFViewerComponent"))
export const StaticPDF = () => {
return (
<Suspense fallback={<p>Loading...</p>}>
<AnyName />
</Suspense>
);
};
# MDX Page
### Content
<BrowserOnly>
{() => <StaticPDF />}
</BrowserOnly>
import { StaticPDF } from "@site/src/components/StaticPDF"
import BrowserOnly from '@docusaurus/BrowserOnly'
import { useEffect } from 'react';
/**
* Observes a given element using ResizeObserver.
*
* @param {Element} [element] Element to attach ResizeObserver to
* @param {ResizeObserverOptions} [options] ResizeObserver options. WARNING! If you define the
* object in component body, make sure to memoize it.
* @param {ResizeObserverCallback} observerCallback ResizeObserver callback. WARNING! If you define
* the function in component body, make sure to memoize it.
* @returns {void}
*/
export default function useResizeObserver(
element: Element | null,
options: ResizeObserverOptions | undefined,
observerCallback: ResizeObserverCallback,
): void {
useEffect(() => {
if (!element || !('ResizeObserver' in window)) {
return undefined;
}
const observer = new ResizeObserver(observerCallback);
observer.observe(element, options);
return () => {
observer.disconnect();
};
}, [element, options, observerCallback]);
}
I just had this specific problem with almost the exact same setup. The differences being that as of now, July 27, 2024, I have more recent versions of React-PDF (9.1.0); webpack (5.93.0); and docusaurus(3.4). That being said, I built my client within a docker container, but the issues encountered were all from the build step, or a result of the build.
This solution I imagine should work also for a Next.js app that has static site generation issues (replace lazy with dynamic, and maybe also browserOnly with something else) because the plugin workaround you listed above led me to a solution to the build issue, but created a render issue, which is what the Promise.withResolvers part from the #1508 thread is for. Then, the page rendered correctly and the component could input a pdf to load, but could not load it, which led to the worker import workaround, which led to resize issues, which led to recreating the useResizeObserver hook and then it all finally worked:
- do an entirely clean
npx
for the docusaurus;- reinstall all packages EXCEPT for the @wojtekmaj/react-hooks;
- keep all things related to react-pdf isolated as a single component; do NOT add configuration for webpack;
- within the script for the component, add this after imports and before pdfjs gets the worker:
if (typeof Promise.withResolvers === "undefined") { if (window) { 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 } } } }
- import your worker directly from a CDN, and match the version exactly by using the version prop:
pdfjs.GlobalWorkerOptions.workerSrc = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.mjs`
- make sure the PDF viewer component is the default export within the script (rafce not rafc);
- create a loader component and lazyload the PDF viewer component:
import React, { lazy, Suspense } from 'react' const AnyName = lazy(() => import("./PDFViewerComponent")) export const StaticPDF = () => { return ( <Suspense fallback={<p>Loading...</p>}> <AnyName /> </Suspense> ); };
- import that component into the MDX file, and wrap it in browseronly:
# MDX Page ### Content <BrowserOnly> {() => <StaticPDF />} </BrowserOnly> import { StaticPDF } from "@site/src/components/StaticPDF" import BrowserOnly from '@docusaurus/BrowserOnly'
- recreate useResizeObserver hook as a separate file from @wojtekmaj source code:
import { useEffect } from 'react'; /** * Observes a given element using ResizeObserver. * * @param {Element} [element] Element to attach ResizeObserver to * @param {ResizeObserverOptions} [options] ResizeObserver options. WARNING! If you define the * object in component body, make sure to memoize it. * @param {ResizeObserverCallback} observerCallback ResizeObserver callback. WARNING! If you define * the function in component body, make sure to memoize it. * @returns {void} */ export default function useResizeObserver( element: Element | null, options: ResizeObserverOptions | undefined, observerCallback: ResizeObserverCallback, ): void { useEffect(() => { if (!element || !('ResizeObserver' in window)) { return undefined; } const observer = new ResizeObserver(observerCallback); observer.observe(element, options); return () => { observer.disconnect(); }; }, [element, options, observerCallback]); }
This should make everything work. I am very tired right now though and may have forgotten to mention other things I did, but hopefully this helps you and others who have the same issue.
For me, this worked:
pdfjs.GlobalWorkerOptions.workerSrc = https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.mjs
;
and adding the dynamic import:
const PdfViewer = dynamic(
() => import('../../../components/pdfViewer/component').then((mod) => mod.PdfViewer as any),
{ ssr: false }
);
Thank you!
This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this issue will be closed in 14 days.
Before you start - checklist
Description
Context: using
react-pdf
in the latest Docusaurus version 3.2.1npm run build
works for the client but not for the server, the following error shows up:However, running
npm start
works without any problems and I can see the PDF rendered correctly in the Docusaurus website.Steps to reproduce
npx create-docusaurus@latest my-website classic
npm install react-pdf
src/components/PdfViewer.jsx
(I've also tried with
<BrowserOnly />
inside the component, but that led to the same issue)docusaurus.config.js
:(reference from: https://github.com/syed-ahmed/docusaurus-plugin-react-pdf/blob/main/src/index.ts#L31-L42)
Expected behavior
The build succeeds.
Actual behavior
The build fails with the above mentioned error message.
Additional information
Potentially related issues & comments:
Environment