embroider-build / ember-auto-import

Zero config import from npm packages
Other
360 stars 108 forks source link

How to import loader generated chunk file? #311

Open musaffa opened 3 years ago

musaffa commented 3 years ago

This issue is related to ef4/demonstrate-pdfjs#4.

When using prepend feature of fingerprint in production mode (for CDN), it generates a link with http://localhost:4200/assets string prepended twice in the worker file location. Like this:

http://localhost:4200/assets/http://localhost:4200/assets/bdd7918188e61b7ab667.worker-30c87aa8d07dd8e121d7df9cd499b0f6.js

I did an investigation to find the source of this problem. Pdfjs has a webpack support file. In that file, PdfjsWorker is loaded by worker-loader in this line:

var PdfjsWorker = require('worker-loader!./build/pdf.worker.js');

This is worker-loader in inline loading mode. This import creates the problematic link above.

Since inline worker loader creates the problem, I tried to load the worker in my code by worker-loader configuration:

autoImport: {
  webpack: {
    module: {
      rules: [
        {
          test: /\.worker\.js$/,
          loader: 'worker-loader'
        }
      ]
    }
  }
}

The loader successfully creates a chunk file of the worker file in the assets directory. Now in my code:

// pdf-viewer.js
....
....
// the codes below resembles pdfjs/webpack.js

let PdfJs = await import('pdfjs-dist/build/pdf');

// need to know this import path
let PdfjsWorker = await import('path-to-worker-chunk-file-created-by-worker-loader');

if (typeof window !== "undefined" && "Worker" in window) {
  pdfjs.GlobalWorkerOptions.workerPort = new PdfjsWorker();
}

this.doc = await PdfJs.getDocument(this.documentUrl).promise;
....
....

Now how do I import the chunk file generated by the loader in my code?

ef4 commented 3 years ago

If your code, you would say something like await import('pdfjs-dist/build/pdf.worker'). You always use the unbundled name of the module you want, and let webpack rewrite it to the bundled name.

musaffa commented 3 years ago

@ef4 We have to use webpack's worker-loader to import pdf.worker properly. Without worker-loader, the code you suggested becomes this:

let PdfJs = await import('pdfjs-dist/build/pdf');
let PdfjsWorker = await import('pdfjs-dist/build/pdf.worker');

if (typeof window !== "undefined" && "Worker" in window) {
  pdfjs.GlobalWorkerOptions.workerPort = new PdfjsWorker();
}

this.doc = await PdfJs.getDocument(this.documentUrl).promise;

It creates the following error:

Uncaught (in promise) TypeError: PdfjsWorker is not a constructor

So we have to use worker-loader. When worker-loader configuration is set in webpack config, the loader creates its own chunk for the pdf worker. This chunk is created independently of await import. So simple await import won't work for this chunk. I also tried the inline mode of worker-loader but it didn't work.

ef4 commented 3 years ago

Right, I was assuming you already have the worker-loader configured in your webpack config.

It seems the real issue here is the double-prepending bug. Are you using broccoli-asset-rev to do the prepending? That is a likely culprit.

musaffa commented 3 years ago

Yes. It's a standard Ember app using prepend of fingerprint config in ember-cli-build.js.

The issue ef4/demonstrate-pdfjs#4 describes the steps to reproduce this problem in your demonstrate-pdfjs app.

musaffa commented 3 years ago

Webpack support file of PdfJs creates a chunk file for pdf-worker with this line.

var PdfjsWorker = require('worker-loader!./build/pdf.worker.js');

This inline mode of worker-loader appends the following code in the chunk file (Production build, prettified):

function(e, t, r) {
  e.exports = function() {
    return new Worker(r.p + "http://localhost:4200/assets/bdd7918188e61b7ab667.worker-30c87aa8d07dd8e121d7df9cd499b0f6.js")
  }
}

The value of r.p is http://localhost:4200/assets and so the double prepend.

maartenparmentier commented 3 years ago

We just ran into this issue as well. Following

GCheung55 commented 3 years ago

@musaffa @maartenparmentier did you reach a solution? I'm having issues with loading PDF.js as well.

After adding worker-loader, I had regeneratorRuntime is undefined. Did you see a similar issue?

musaffa commented 3 years ago

Not yet.