react-pdf-viewer / starter

Some boilerplates to use React PDF viewer component
https://react-pdf-viewer.dev
25 stars 30 forks source link

External worker dependency (for Next.js) #30

Open dmudro opened 3 years ago

dmudro commented 3 years ago

The Next.js starter suggest an external dependency on the pdf worker:

...
<Worker workerUrl="https://unpkg.com/pdfjs-dist@2.9.359/build/pdf.worker.js">
...

Since we already have the worker file in node_modules/pdfjs-dist it would be more feasible to use the local file and avoid the external http call and to improve the integrity of pdfjs-dist version in the first place.

Any ideas what's the best approach here?

I appreciate this might not be directly related to the pdf viewer code base as such. Perhaps a separate webpack bundle with the worker could do the job here.

phuocng commented 3 years ago

@dmudro Since NextJS allows us to add custom Webpack configurations, you can follow this guide https://react-pdf-viewer.dev/examples/compile-and-set-the-worker-source-with-webpack/

dmudro commented 3 years ago

@phuoc-ng sounds good in theory but if you follow your guide, there are some Next.js specificities probably not compatible with the suggested solution for "pure webpack". Namely this part of the custom webpack config:

entry: {
    main: './src/index.tsx',
    'pdf.worker': path.join(__dirname, './node_modules/pdfjs-dist/build/pdf.worker.js'),
},

What's the Next.js equivalent? Even if this worked:

config.entry['pdf.worker'] = path.join(__dirname, './node_modules/pdfjs-dist/build/pdf.worker.js');

... where is the "worker bundle" accessible from?

Obviously <Worker workerUrl="/pdf.worker.bundle.worker.js">...</Worker>; is not going work with Next.js public folder. Any thoughts?

Basically all we need to to do is to be able to access the pdf.worker.min.js so I thought to use the CopyWebpackPlugin. In theory it does not need to be webpack and any custom script would do it so I can eventually reference my local worker:

<Worker workerUrl="/_next/static/pdf.worker.worker.min.js">...</Worker>;

My concern is if it is right to write into .next folder though: https://github.com/vercel/next.js/discussions/30439

raibima commented 3 years ago

if your nextjs app already uses webpack v5, you can simply do this: (no extra configuration needed)

const workerUrl = new URL('../node_modules/pdfjs-dist/build/pdf.worker.js', import.meta.url).toString();

<Worker workerUrl={workerUrl}></Worker>
dmudro commented 3 years ago

Cheers @raibima, I tried asset modules as suggested with some tweaks around node_module path:

const workerUrl = new URL('node_modules/pdfjs-dist/build/pdf.worker.js', import.meta.url); // no ../node_modules
...
<Worker workerUrl={workerUrl.href}></Worker>

Next.js 11 Webpack 5 would pick up the asset and put .js inside the .next/ build dir. workerUrl.href would then be something like http://localhost:3000/_next/<random_file_name>.js. Nice.

So it should work... However, the local dev server does not serve files off the root of the build dir, gives 404 back. I reckon it would need to be inside .next/static (or another subfolder).

Now even if it all worked, I am not quite sure if using node_modules in the path inside a JSX module is the right thing to do?

Next.js 12 Same code, but now workerUrl is empty. Probably related to the fact that URL imports are now experimental in v12 and there is a whole config around their security model: https://nextjs.org/docs/api-reference/next.config.js/url-imports#asset-imports

Given asset modules do not seem to be production ready in Next.js 12 yet, the right strategy seems to be waiting for how that experimental feature pans out and then reconsider. Until then I will most likely go with my CopyPlugin solution which works with v12.

Perhaps copying assets on my own into .next buil dir is not too bad.

@phuoc-ng you might want to reflect the new versions of Webpack and Next.js in your starter guide

raibima commented 3 years ago

not sure why it doesn't work for you in dev but I use it in dev + prod just fine using the snippet I shared previously (nextjs 12). In my case, it'll be served under:

/_next/static/media/pdf.worker.3341b606.js

So nextjs automatically does the copying / "bundling" from node_modules/pdfjs-dist to .next/static/media

dmudro commented 3 years ago

Alright. I'll revisit to make sure I didnt have something locally conflicting with asset modues and will report back here if I find out anything.