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

Render breaks in nextjs 14.1.0 - ReferenceError: Can't find variable: exports leads to "Failed to load PDF file." #1699

Open
3 of 4 tasks
ptpittman opened this issue Jan 19, 2024 · 13 comments
Labels
bug Something isn't working

Comments

@ptpittman
Copy link

Before you start - checklist

  • I followed instructions in documentation written for my React-PDF version
  • I have checked if this bug is not already reported
  • I have checked if an issue is not listed in Known issues
  • If I have a problem with PDF rendering, I checked if my PDF renders properly in PDF.js demo

Description

I have a site using nextjs app dir, rendering PDFs in a client component. Was working fine up to 14.0.3. Upgrading to 14.1.0, it now throws an error on client side and cannot load the PDF.

Minimally, my components loads the following outside of the component:

import { pdfjs } from "react-pdf";

import { Document, Page } from "react-pdf";
import "react-pdf/dist/Page/AnnotationLayer.css";

pdfjs.GlobalWorkerOptions.workerSrc = new URL(
  "pdfjs-dist/build/pdf.worker.min.js",
  import.meta.url
).toString();

As recommended in docs. I tried moving the pdfjs.GlobalWorkerOptions line into a useEffect to fire on load but this only delayed the error slightly.

I build and deploy using pnpm. I noted the instruction in the docs to add a .npmrc with "public-hoist-pattern[]=pdfjs-dist", which I hadn't previously had or apparently needed, but this doesn't resolve the issue.

Steps to reproduce

No public reproduction as I had to revert. Can deploy a test repo if needed.

Expected behavior

PDF displays first page

Actual behavior

Page displays "Failed to load PDF file", browser console

Additional information

Console errors are as follows:

[Error] ReferenceError: Can't find variable: exports (pdf.worker.min.db5d8e2a.js, line 22)
[Error] ReferenceError: Can't find variable: exports
	Global Code (pdf.worker.min.db5d8e2a.js:22)
[Error] Warning: Error: Setting up fake worker failed: "undefined is not an object (evaluating 'window.pdfjsWorker.WorkerMessageHandler')".
	(anonymous function) (app-index.js:35)
	(anonymous function) (hydration-error-info.js:41)
	printWarning (warning.js:26)
	warning (warning.js:45)
	onLoadError (Document.js:315)
	(anonymous function) (Document.js:372)
	commitHookEffectListMount (react-dom.development.js:18071)
	commitHookPassiveMountEffects (react-dom.development.js:19742)
	commitPassiveMountOnFiber (react-dom.development.js:19826)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19889)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19918)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)
	commitPassiveMountOnFiber (react-dom.development.js:19824)
	recursivelyTraversePassiveMountEffects (react-dom.development.js:19808)

Environment

  • Browser (if applicable): All browsers
  • React-PDF version: 7.7.0
  • React version: 18.2.0
  • Webpack version (if applicable): Nextjs Default
  • Next.js: 14.1.0
@ptpittman ptpittman added the bug Something isn't working label Jan 19, 2024
@wojtekmaj
Copy link
Owner

If the package worked before and stopped working without any changes on our side, it's a Next.js regression and should be reported to them.

I'm not surprised this happened, they notoriously break packages because of the amount of hacks they ship to production.

@ptpittman
Copy link
Author

No doubt - they're playing around a lot with barrel import optimization at the moment and Material UI was broken entirely for 14.0.4. But to help me take this up with them, I do see various tickets throughout history related to pdfjs's lack of a default export sometimes causing problems. Looking at the code these days, it doesn't seem to be the case – is there anything I should look more closely at? (My import method above is correct, right?)

@wojtekmaj
Copy link
Owner

I'm curious how #1690 would perform now that PDF.js is ESM first. Unfortunately we're not ready for a pre-release even, let alone full release.

@kevsjh
Copy link

kevsjh commented Jan 21, 2024

i was facing the same issue as well in nextjs 14.1.0. Changing the import worker to external cdn fixes it for me

pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`;

"react-pdf": "^7.7.0",
"next": "^14.1.0",

@ptpittman
Copy link
Author

Nice! Good workaround for now. Definitely points to their webpack optimizations continuing to do new wild and unplanned things.

@lujun2
Copy link

lujun2 commented Feb 3, 2024

instead of CDN, I use local assets instead

// package.json
{
  "script": {
    "postinstall": "node ./postinstall.js"
  }
}
// postinstall.js
const path = require('path');
const fs = require('fs');

const pdfjsDistPath = path.dirname(require.resolve('pdfjs-dist/package.json'));
const pdfWorker = path.join(pdfjsDistPath, 'build', 'pdf.worker.min.js');

fs.copyFileSync(pdfWorker, './public/js/pdf.worker.min.js');
// PDFViewer.tsx
'use client';

import { Document, Page, pdfjs } from 'react-pdf';
pdfjs.GlobalWorkerOptions.workerSrc = '/js/pdf.worker.min.js';

@talhaibnmahmud
Copy link

instead of CDN, I use local assets instead

// package.json
{
  "script": {
    "postinstall": "node ./postinstall.js"
  }
}
// postinstall.js
const path = require('path');
const fs = require('fs');

const pdfjsDistPath = path.dirname(require.resolve('pdfjs-dist/package.json'));
const pdfWorker = path.join(pdfjsDistPath, 'build', 'pdf.worker.min.js');

fs.copyFileSync(pdfWorker, './public/js/pdf.worker.min.js');
// PDFViewer.tsx
'use client';

import { Document, Page, pdfjs } from 'react-pdf';
pdfjs.GlobalWorkerOptions.workerSrc = '/js/pdf.worker.min.js';

I used a slightly modified version and resolved the issue for me (with bun)

{
  "script": {
    "postinstall": "bun ./scripts/postinstall.mjs"
  }
}
// scripts/postinstall.mjs
import fs from "node:fs";
import path from "node:path";

const pdfjsDistPath = path.dirname(
    path.resolve("node_modules/pdfjs-dist/package.json")
);
const pdfjsWorkerPath = path.join(pdfjsDistPath, "build", "pdf.worker.min.js");

fs.copyFileSync(pdfjsWorkerPath, "public/pdf.worker.min.js");
"use client";

pdfjs.GlobalWorkerOptions.workerSrc = "/pdf.worker.min.js";

@cyrus-za
Copy link

I am running into this and switching to a CDN does change the error message but it still has an error. See nrwl/nx#21611

I also tried the script to copy the file to /public but same issue.

739.js from Terser
Unexpected token: punc ({) [739.js:4502,26]
    at js_error (node_modules/.pnpm/next@14.0.4_@babel+core@7.23.9_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/terser/bundle.min.js:1:32780)

@jianyuan
Copy link

jianyuan commented Feb 20, 2024

Alternatively, I solved this by using the copy-webpack-plugin.

// next.config.js
const path = require("path")
const CopyPlugin = require("copy-webpack-plugin")

/** @type {import('next').NextConfig} */
const nextConfig = {
  // ...
  webpack: (config) => {
    config.plugins.push(
      new CopyPlugin({
        patterns: [
          {
            from: require.resolve("pdfjs-dist/build/pdf.worker.min.js"),
            to: path.join(__dirname, "public/static/js"),
          },
        ],
      }),
    )
  }
}

Then,

pdfjs.GlobalWorkerOptions.workerSrc = "/static/js/pdf.worker.min.js"

@wojtekmaj
Copy link
Owner

@jianyuan Your solution looks REALLY good! I think it can be safely recommended as a secondary option if the primary one doesn't work well.

@ianschmitz
Copy link

Does /static/js have an aggressive Cache-Control header like /static/chunks does? If so this would break in the future when this worker file changes as it would be cached and not fetched.

@jianyuan
Copy link

@ianschmitz You can include the version in the filename:

// next.config.js
const path = require("path")
const CopyPlugin = require("copy-webpack-plugin")
const pdfjs = require('react-pdf')

/** @type {import('next').NextConfig} */
const nextConfig = {
  // ...
  webpack: (config) => {
    config.plugins.push(
      new CopyPlugin({
        patterns: [
          {
            from: require.resolve("pdfjs-dist/build/pdf.worker.min.js"),
            to: path.join(__dirname, `public/static/js/pdf.worker-${pdfjs.version}.min.js`),
          },
        ],
      }),
    )
  }
}

Then,

pdfjs.GlobalWorkerOptions.workerSrc = `/static/js/pdf.worker-${pdfjs.version}.min.js`

@thecil
Copy link

thecil commented Mar 6, 2024

i was facing the same issue as well in nextjs 14.1.0. Changing the import worker to external cdn fixes it for me

pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`;

"react-pdf": "^7.7.0", "next": "^14.1.0",

This solution worked for me on production (vercel). Thanks @kevsjh.

    "next": "14.1.0",
    "react-pdf": "^7.7.1",

next.config.mjs

/** @type {import('next').NextConfig} */
const nextConfig = {
 webpack: (config) => {
   config.resolve.alias.canvas = false;

   return config;
 }
};

export default nextConfig;

then at my PreviewDocument.tsx component

"use client";

import { Document, Page } from "react-pdf";
import { pdfjs } from "react-pdf";
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`;

// ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

9 participants