Create react app - how to copy pdf.worker.js file from pdfjs-dist/build to your project's output ...
Categories:
Integrating PDF.js Worker in Create React App: A Comprehensive Guide
Learn how to correctly copy the pdf.worker.js
file from pdfjs-dist/build
to your Create React App project's output folder, ensuring react-pdf
functions properly.
When working with PDF documents in a React application, react-pdf
is a popular library that leverages Mozilla's PDF.js under the hood. A common hurdle developers face is ensuring that the pdf.worker.js
file, essential for PDF rendering, is correctly placed and accessible in the production build. This article will guide you through various methods to achieve this in a Create React App (CRA) environment, from simple copy commands to more robust build process integrations.
Understanding the Need for pdf.worker.js
The pdf.worker.js
file is a Web Worker script that PDF.js uses to perform CPU-intensive tasks like parsing and rendering PDF pages in a separate thread. This prevents the main UI thread from freezing, ensuring a smooth user experience. Without this worker script being correctly loaded, react-pdf
will fail to render documents, often resulting in errors like 'Worker was not found' or 'Failed to load PDF worker'.
By default, react-pdf
expects this worker file to be available at a specific path relative to your application's root or served from a CDN. In a CRA project, the build process bundles your application, and external assets like pdf.worker.js
need explicit handling to be included in the final output.
flowchart TD A[React App Component] --> B{react-pdf Library} B --> C{PDF.js Core} C --> D["Load pdf.worker.js"] D --"Worker not found"--> E[Rendering Failure] D --"Worker found"--> F[PDF Rendered Successfully] subgraph Build Process G[Source Code] --> H[Webpack/CRA Build] H --> I["Output: index.html, bundle.js"] I --"Missing pdf.worker.js"--> E I --"Includes pdf.worker.js"--> F end style E fill:#fdd,stroke:#333,stroke-width:2px style F fill:#dfd,stroke:#333,stroke-width:2px
Flowchart illustrating the role of pdf.worker.js in the React-PDF rendering process.
Method 1: Using pdfjs-dist
's webpack-pdfjs-worker-loader
(Recommended for CRA)
The pdfjs-dist
package provides a dedicated Webpack loader that simplifies the inclusion of the worker. This is often the cleanest and most robust solution for CRA projects, as it integrates directly into the build system.
1. Install the loader
First, install the webpack-pdfjs-worker-loader
package. Note that this package is typically used with Webpack 4. For Webpack 5 (used in newer CRAs), you might need to adjust or use a different approach if the loader doesn't work out of the box. However, react-pdf
often handles this internally if configured correctly.
2. Configure react-pdf
The react-pdf
library allows you to specify the worker source. The most common and recommended way is to set pdfjs.GlobalWorkerOptions.workerSrc
.
import { pdfjs } from 'react-pdf';
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`;
// Or, if you want to bundle it directly (requires Webpack configuration or a custom CRA setup):
// pdfjs.GlobalWorkerOptions.workerSrc = new URL(
// 'pdfjs-dist/build/pdf.worker.min.js',
// import.meta.url,
// ).toString();
// Your React component
function MyPdfViewer() {
// ...
}
Setting GlobalWorkerOptions.workerSrc
for react-pdf
.
unpkg.com
for pdf.worker.min.js
is often the simplest solution, as it bypasses local build configuration issues entirely. Ensure the version matches your pdfjs-dist
dependency.Method 2: Manual Copying during Build (Custom CRA Setup)
If you need to host the worker file locally and are using a CRA setup that allows for custom build scripts (e.g., by ejecting or using craco
), you can manually copy the file. This method ensures the worker is always served from your own domain.
1. Install copyfiles
(or similar utility)
Install a utility like copyfiles
to easily copy files as part of your build script.
2. Add a copy script to package.json
Modify your package.json
to include a pre-build script that copies the worker file. This script should run before your main build command.
3. Configure react-pdf
to use the local worker
Update your react-pdf
configuration to point to the locally copied worker file.
{
"name": "my-react-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-pdf": "^7.7.0",
"pdfjs-dist": "^3.11.174"
},
"scripts": {
"prebuild": "copyfiles -f node_modules/pdfjs-dist/build/pdf.worker.min.js build",
"build": "react-scripts build",
"start": "react-scripts start",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"devDependencies": {
"copyfiles": "^2.4.1"
}
}
Adding a prebuild
script to package.json
to copy pdf.worker.min.js
.
import { pdfjs } from 'react-pdf';
// Assuming the file is copied to the root of your build folder (e.g., /build/pdf.worker.min.js)
pdfjs.GlobalWorkerOptions.workerSrc = `${window.location.origin}/pdf.worker.min.js`;
// Or, if you copy it to a 'workers' subfolder in build:
// pdfjs.GlobalWorkerOptions.workerSrc = `${window.location.origin}/workers/pdf.worker.min.js`;
function MyPdfViewer() {
// ...
}
Configuring react-pdf
to use the locally copied worker file.
package.json
scripts and assumes your build output directory is build
. If you've ejected CRA or use craco
, you might have more direct control over Webpack configuration to achieve this more elegantly.Method 3: Using public
Folder (Simple but Less Flexible)
For simpler cases, you can place the pdf.worker.js
file directly into your CRA project's public
folder. Files in the public
folder are copied as-is to the build output root.
1. Copy the worker file to public
Manually copy node_modules/pdfjs-dist/build/pdf.worker.min.js
to your project's public
directory. You might want to rename it or place it in a subfolder like public/workers
.
2. Configure react-pdf
Point GlobalWorkerOptions.workerSrc
to the path relative to your public
folder.
import { pdfjs } from 'react-pdf';
// If copied to public/pdf.worker.min.js
pdfjs.GlobalWorkerOptions.workerSrc = `${process.env.PUBLIC_URL}/pdf.worker.min.js`;
// If copied to public/workers/pdf.worker.min.js
// pdfjs.GlobalWorkerOptions.workerSrc = `${process.env.PUBLIC_URL}/workers/pdf.worker.min.js`;
function MyPdfViewer() {
// ...
}
Configuring react-pdf
to use the worker from the public
folder.
process.env.PUBLIC_URL
variable correctly resolves to the base URL of your application, making this approach robust even if your app is served from a subpath.