React-pdf: <hash>.worker.js returns Error 404

Created on 6 Nov 2017  ·  29Comments  ·  Source: wojtekmaj/react-pdf

Hi,

When i try to use the webpack.entry import my app crashes and I can see a network request going to the current path/cba38462455a43d162b5.worker.js which is returning 404.

I am importing import { Document, Page } from 'react-pdf/build/entry.webpack'

Here is my webpack config:

const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');

const settings = {
  entry: {
    bundle: [
      'babel-polyfill',
      "./src/frontend/index.js"
    ]
  },
  output: {
    filename: "[name].js",
    path: path.resolve("build")
  },
  resolve: {
    extensions: [".js", ".jsx", ".json", ".css"]
  },
  devtool: "eval-source-map",
  module: {
    rules: [
      {
        test: /\.(js|jsx)?$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          presets: [
            ["es2015", { modules: false }],
            "stage-0",
            "react"
          ],
          plugins: [
            "transform-decorators-legacy",
            "transform-node-env-inline"
          ],
          env: {
            development: {
              presets: ['react-hmre'],
              plugins: ["react-hot-loader/babel"]
            }
          }
        }
      },
      {
        test: /\.css$/,
         use: [ 'style-loader', 'css-loader','less-loader'],
        include: [/flexboxgrid/,/react-star-rating/]
      }
    ]
  },
  devServer: {
    contentBase: path.resolve("src/www"),
    publicPath: "http://localhost:8080/", // full URL is necessary for Hot Module Replacement if additional path will be added.
    quiet: false,
    hot: true,
    historyApiFallback: true,
    inline: true
  },
  plugins: [
    new webpack.NamedModulesPlugin(),
    new webpack.LoaderOptionsPlugin({
      debug: true
    }),
  ],
};

module.exports = settings;

question

Most helpful comment

I got it working !
as i am using commonjs as set in my tsconfig
I must import it like this:
import {Document, Page} from 'react-pdf/dist/umd/entry.webpack'
not like
import {Document, Page} from 'react-pdf' //BAD not working !

So its working now in my node/ express app

in my other app that just users dev server and react static
I am using esnext, that is set in my tsconfig.json
there i am importing it like

import {Document, Page} from 'react-pdf';

that works!

This means depending on the what module is set to will require it to be imported differently.

for commonjs
` import {Document, Page} from 'react-pdf'

for esnext
import {Document, Page} from 'react-pdf/dist/umd/entry.webpack'

All 29 comments

Hey @benoj, sorry for the late reply. There's nothing in your webpack config that raises my concerns. Is there any file in your output folder with .worker.js at the end? There should be one if everything is set up correctly.

@wojtekmaj no worries - I have worked out the issue but not sure how to resolve it?

The app works fine when I load / as the worker is loaded from /<hash>.worker.js but if i load on /subresource then i get a 404 for the /subresource/<hash>.worker.js this is because my devserver is serving all files from the build folder where the worker is generated. However it looks like the worker is being pulled in on a relative route rather than an absolute route.
Anyway to override this?

@benoj I don't know whether it's a pretty solution, but if it only affects your devServer, you can use devServer proxy for re-directing requests that are going wrong way.

@wojtekmaj no it affects the production app also.

The app is a single page app using react router. When I open the app at the non root level then the request for the worker goes to the wrong path.

Basically could be fixed by using an absolute path to /{hash}.worker.js. Is it possible to override the current relative path?

Also do you know how the hash is calculated? And if it is constant?

Ben

Hmmm... I believe that all files dynamically imported by Webpack share the same logic, so you might have a problem with all bundles downloaded dynamically while being anywhere else but in /. Perhaps you're missing output.publicPath in your Webpack configuration?

I have updated my webpack (above) with the following:

  output: {
    filename: "js/[name].js",
    path: path.resolve("build"),
    publicPath: '/js'
  }

but i can see the [hash].worker.js isnt being built in the /js folder and the request from the app is now going to /subresource/js/[hash].worker.js so still resolving to 404.

but confused as to how to solve this? my webpack seems fairly standard - not sure why other people are not seeing this?

Update: Got it working. Would be keen to hear back on your opinion of this solution:

webpack updated to build my own pdf.worker

 entry: {
    bundle: [
      'babel-polyfill',
      "./src/frontend/index.js"
    ],
    'pdf.worker': 'pdfjs-dist/build/pdf.worker.entry'
  },
  output: {
    filename: "js/[name].js",
    path: path.resolve("build"),
    publicPath: 'js/'
}

setting workerSrc manually to the js output path

import Document from 'react-pdf/build/Document';
import Outline from 'react-pdf/build/Outline';
import Page from 'react-pdf/build/Page';
import React from 'react';
const pdfjs = require('pdfjs-dist');
pdfjs.PDFJS.workerSrc = '/js/pdf.worker.js';

Hmmm, not bad workaround at all!
I think that this should be more talked through at webpack-loader's repository though. I'm by no means a Webpack expert so perhaps they will be able to find better solutions and maybe even some fixes to how it works, if workers are not handled the same way normal bundles are.

By the way, support for setting your own PDFJS settings in a slightly more convenient way is coming soon.

Hey @benoj,
setting custom PDF.js settings without the need of hacks is now live in React-PDF 2.3.0. It's not much different:

import { setOptions, <WhateverElseYouNeed> } from 'react-pdf';

setOptions({
  workerSrc: '/js/pdf.worker.js',
});

Hope you like it!

@wojtekmaj Awesome will give it a go! Thanks :)

Not sure this is working as intended.
Tried using setOptions method, to no avail.
Still generating a <hash>.worker.js file in the build root...which is not being served by the backend.
Was not having this problem with prod webpack config (was not prepending a hash), odd it is happening in dev... will report back if i figure out what is causing it to begin with.

I resorted to @benoj original solution as a work around.

The important thing to note is that entry.webpack sole purpose is to enable PDF.js worker with zero configuration from your side. If you plan to disable it, you should not use entry.webpack, just a normal entry.

I do not want to disable it, just have a bit more control over how it is being dynamically imported/referenced.

I presume pdfjs is being imported/attached to window?
Was wondering how setOptions ensures it is being configured being called without any context...
It appears to work by importing pdfjs manually and specifying workerSrc, as mentioned above :

// importing these on their own
import Document from 'react-pdf/build/Document';
import Page from 'react-pdf/build/Page';
// configuring pdfjs
const pdfjs = require('pdfjs-dist');
pdfjs.PDFJS.workerSrc = '/js/pdf.worker.js';

EDIT:

Looking at the source, think my problem was importing from entry.webpack
The following is working as intended!

import { Document, Page, setOptions } from "react-pdf/build/entry";

setOptions({
  workerSrc: "/js/worker.pdf.js"
});

That looks okay to me ;) That if course requires you to do more configuration because you need to copy the loader yourself.

By the way, that's default entry point so you can just write from 'react-pdf' :)

Facing this issue myself. ReactPDF is trying to load the worker at a relative path rather than absolutely against the domain. Anyone got any ideas how to sort it? I'm not all too familiar with webpack, so am using Laravel Mix

Also ended up here -- my app serves static assets from /static, but I can't get webpack to generate the workerjs file there.

@joshbrw, @tjwebb, please refer to the comment above. You don't need to force Webpack to put files anywhere you don't want them. I believe this is exactly what you are looking for - it should tell React-PDF where to look for the worker file.

The workout around in above comment doesn't work anymore as setOptions seems to have been deprecated or moved somewhere in the mean time. Reading the documentation leads to believe that the following could work:

import { pdfjs } from 'react-pdf';
pdfjs.GlobalWorkerOptions.workerSrc = `/path/to/your/worker.js`

It however does not work, as the path I see being tried in DevTools is still relative to the current url and is not absolute.

We are using this at our work to render PDF within our react app. It works fine locally, whether we use 'react-pdf' import, or 'react-pdf/dist/entry.webpack' or even pdfjs.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js'; (where ' = `), but neither 1st or 3rd option work on our production.

On production, using 'react-pdf' import, pdf.worker.js is called from URL/pdf.work.js and is (status) "cancelled". Then we tried using the CDN and the file successfully loads, but in both situations, our tab freezes and eventually crashes. There is a message in devTool Sources "paused before potential out-of-memory crash".

We were forced to take it out, no idea what is going on.

I have read through the following issues: 371, 378 - no answer, even 8305 on pdf.js

Any updates?
I encounter similar issue but the same - I don't see any error in the console and I don't see 404 as return value.
when I use: import { Document, Page } from "react-pdf"; I manage to see the pdf file
but when I use: import { Document, Page } from 'react-pdf/dist/entry.webpack'; I can't see the file.
onDocumentLoadSuccess never called and It stuck on loading with Loading PDF… message.
None of the following method are called:

  • onLoadError (inside document component)
  • onSourceError (inside document component)
  • onLoadError (inside page component)
  • onRenderError (inside page component)
  • onLoadProgress (inside page component)

@b-asaf Sometimes, specially on modern apps which have client-side routing instead of 404, a HTML page is returned, so you don't see actual HTTP 404 error code, you see 200.

its so tricky, you can use default cdn from PDF.js

import { pdfjs } from 'react-pdf';
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;

I thank for all answers here but rather than using CDN

import { pdfjs } from 'react-pdf';
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;

I would like to use the output file of my project to avoid cross-domain request but it doesn't work if I set

pdfjs.GlobalWorkerOptions.workerSrc = '/dist/vendors~pdfjsWorker.js';

I liked a lot this tool but for me it seems it's an error to ignore absolute path. I am working on a SPA app and if I try to access http://example.com/check/id/language the package doesn't work.

Thanks.

This is not a CDN issue , i have it running in one of my local apps but not the other.

In one of my apps, its running through web-pack dev server , using react static , this works.

The other has a node/express backend bundled with webpack , the frontend is again React , this does not work.

the config for the pdf stuff is the same ,
this tells me there is something i need to do with my node/express web-pack setup,
maybe something to do with the express routes.

anyways; i'll get back once i work this out, or if anyone knows what's up, please share.

I got it working !
as i am using commonjs as set in my tsconfig
I must import it like this:
import {Document, Page} from 'react-pdf/dist/umd/entry.webpack'
not like
import {Document, Page} from 'react-pdf' //BAD not working !

So its working now in my node/ express app

in my other app that just users dev server and react static
I am using esnext, that is set in my tsconfig.json
there i am importing it like

import {Document, Page} from 'react-pdf';

that works!

This means depending on the what module is set to will require it to be imported differently.

for commonjs
` import {Document, Page} from 'react-pdf'

for esnext
import {Document, Page} from 'react-pdf/dist/umd/entry.webpack'

@nickjohngray I'm trying to import from react-pdf/dist/umd/entry.webpack, but Typescript is complaining that the submodule does not exist. I have @types/react-pdf version 4.0.6 installed, which appears to be the latest version... how did you work around the type problems?

If my typecheck takes a long time to complete, I can verify that the worker is compiling fine and the PDF is loading and displaying when I use dist/umd, but once the typecheck completes it errors out, and my IDE is also complaining:

Error:(4, 30) TS7016: Could not find a declaration file for module 'react-pdf/dist/umd/entry.webpack'. 
  E:/Users/Rob/workspace/gTove/node_modules/react-pdf/dist/umd/entry.webpack.js' implicitly has an 'any' type.
  If the 'react-pdf' package actually exposes this module, consider sending a pull request to amend 'https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/react-pdf`

hi @RobRendell
i did not have a type error .
if this type error is stopping you , Use the any type and see if it works.

@nickjohngray I can't use any as a type (it's an import statement), but I can precede the import with a line saying // @ts-ignore to ignore the error. When I do that, everything works fine.

Ideally, I'd like to work out how to add the proper types. I'm trying to extend the module declaration by adding a .d.ts file:

import {pdfjs, Document, Page, Outline} from 'react-pdf';

declare module 'react-pdf/dist/umd/entry.webpack' {
    export {pdfjs, Document, Page, Outline};
}

... but that didn't seem to fix the problem for me. I'm not proficient enough in Typescript to know what's going on with that.

i got a few deadlines to achieve right now. i can help out when i finish
that stuff . the issue must be small , just an annoying type issue .

i noticed in the pass for libs that dont fully support typescript it was
not worth my time working out types for them . my time is limited and i
spend it it on building and fixing kick ass components. i surgest you do
the same . 😀

Thanks Nick.

On Mon, 28 Sep 2020, 8:01 pm Rob Rendell, notifications@github.com wrote:

@nickjohngray https://github.com/nickjohngray I can't use any as a type
(it's an import statement), but I can precede the import with a line saying //
@ts-ignore to ignore the error. When I do that, everything works fine.

Ideally, I'd like to work out how to add the proper types. I'm trying to
extend the module declaration by adding a .d.ts file:

import {pdfjs, Document, Page, Outline} from 'react-pdf';

declare module 'react-pdf/dist/umd/entry.webpack' {
export {pdfjs, Document, Page, Outline};
}

... but that didn't seem to fix the problem for me. I'm not proficient
enough in Typescript to know what's going on with that.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/wojtekmaj/react-pdf/issues/97#issuecomment-699818238,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AD3TSIQUIASADKB6UASTNRDSIAYEZANCNFSM4ECOS2TQ
.

Was this page helpful?
0 / 5 - 0 ratings