embroider-build / embroider

Compiling Ember apps into spec-compliant, modern Javascript.
MIT License
331 stars 137 forks source link

Top-level await is not supported #1948

Open dwickern opened 1 month ago

dwickern commented 1 month ago

Reproduction here: https://github.com/dwickern/ember-pdfjs-reproduction/tree/embroider

The module which imports PDF.js will have its own exports broken. In the reproduction, the application route imports pdf.js. Its export resolves to a promise instead of the route class:

image

This results in an error:

Uncaught Error: Assertion Failed: Failed to create an instance of 'route:application'. Most likely an improperly defined class or an invalid module export.
    at assert (index.js:118:1)
    at InternalFactoryManager.create (index.js:372:1)
    at Proxy.create (index.js:204:1)
    at instantiateFactory (index.js:276:1)
    at lookup (index.js:223:1)
    at Container.lookup (index.js:121:1)
    at ApplicationInstance.lookup (container_proxy.js:19:1)
    at PrivateRouter.getRoute (router.js:183:1)
    at UnresolvedRouteInfoByParam.fetchRoute (router_js.js:714:1)
    at get route (router_js.js:648:1)

If you import PDF.js in a service instead, all @service injections for that service will resolve to a Promise<Service> instead of the service.

There's a related problem with ember-auto-import https://github.com/embroider-build/ember-auto-import/issues/614

ef4 commented 1 month ago

pdf.js. is using top-level await. We can't make that work until we do https://github.com/emberjs/rfcs/pull/938.

A workaround until then is to access pdf.js via dynamic import only:


diff --git a/app/routes/application.js b/app/routes/application.js
index 1c602d9..9555db4 100644
--- a/app/routes/application.js
+++ b/app/routes/application.js
@@ -1,10 +1,10 @@
 import Route from '@ember/routing/route';
-import { getDocument } from 'pdfjs-dist/webpack.mjs';

 const url = '/fw4.pdf';

 export default class ApplicationRoute extends Route {
   async model() {
+    const { getDocument } = await import('pdfjs-dist/webpack.mjs');
     const loadingTask = getDocument({ url });
     return await loadingTask.promise;
   }

This worked for me in your reproduction app.

dwickern commented 1 month ago

PDF.js 4.3.136 just released and they no longer use top-level await, so it works now without the dynamic import.

Related issue https://github.com/mozilla/pdf.js/issues/17245 and fix https://github.com/mozilla/pdf.js/pull/18051