Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.0.189: Top-level await is not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari14" + 2 overrides) #17245

Closed
jiadesen opened this issue Nov 9, 2023 · 38 comments · Fixed by #18051

Comments

@jiadesen
Copy link

jiadesen commented Nov 9, 2023

Attach (recommended) or Link to PDF file here: any

Configuration:

  • Web browser and its version: Google Chrome 119
  • Operating system and its version: macOS 14.1
  • PDF.js version: 4.0.189
  • Is a browser extension: no
  VITE v4.5.0  ready in 457 ms

  ➜  Local:   http://localhost:5273/pdf/
  ➜  Network: http://192.168.10.13:5273/pdf/
  ➜  press h to show help

✘ [ERROR] Top-level await is not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari14" + 2 overrides)

    node_modules/.pnpm/pdfjs-dist@4.0.189/node_modules/pdfjs-dist/build/pdf.mjs:16837:53:
      16837 │ /******/ __webpack_exports__ = globalThis.pdfjsLib = await __webpack_exports__;
            ╵                                                      ~~~~~

4:46:45 PM [vite] error while updating dependencies:
Error: Build failed with 1 error:
node_modules/.pnpm/pdfjs-dist@4.0.189/node_modules/pdfjs-dist/build/pdf.mjs:16837:53: ERROR: Top-level await is not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari14" + 2 overrides)
    at failureErrorWithLog (/Users/xxx/node_modules/.pnpm/esbuild@0.18.20/node_modules/esbuild/lib/main.js:1649:15)
    at /Users/xxx/node_modules/.pnpm/esbuild@0.18.20/node_modules/esbuild/lib/main.js:1058:25
    at /Users/xxx/node_modules/.pnpm/esbuild@0.18.20/node_modules/esbuild/lib/main.js:1525:9
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
@jiadesen
Copy link
Author

jiadesen commented Nov 9, 2023

Export pdfjsLib as follows:

import * as pdfjsLib from "pdfjs-dist";
import * as pdfWorker from "pdfjs-dist/build/pdf.worker.mjs";

// Setting worker path to worker bundle.
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfWorker;

export { pdfjsLib };

@ghenry
Copy link

ghenry commented Nov 9, 2023

Is this a solution @jiadesen ?

I'm getting them same as you as jut trying out v4 in a new project and getting:

[watch] build started (change: "js/pdf_preview/index.js")
✘ [ERROR] Top-level await is currently not supported with the "iife" output format

    node_modules/pdfjs-dist/build/pdf.mjs:16837:53:
      16837 │ ...ck_exports__ = globalThis.pdfjsLib = await __webpack_exports__;
            ╵                                         ~~~~~

See https://elixirforum.com/t/importing-pdf-mjs-into-app-js/59578 with --target=es2022 that is via esbuild. If I use the default of --target=es2017 I get:

✘ [ERROR] Top-level await is not available in the configured target environment ("es2017")

    node_modules/pdfjs-dist/build/pdf.mjs:16837:53:
      16837 │ ...ck_exports__ = globalThis.pdfjsLib = await __webpack_exports__;

Should work or should we go back to v3?

@ghenry
Copy link

ghenry commented Nov 9, 2023

No, it's just how you're importing it. Have switch to that way to confirm that we have the same issue. We do.

@Snuffleupagus
Copy link
Collaborator

Searching for the error message Top-level await is currently not supported with the "iife" output format with Google points to evanw/esbuild#253, which suggests that this unfortunately is a known limitation of the esbuild bundler.

Looking at the MDN compatibility data all modern browsers/environments support top level await, and has done so for awhile, hence the only suggestion that we can really provide is to (if possible) use another bundler instead.

@jiadesen
Copy link
Author

Solved by adding vite configuration:

optimizeDeps: {
    esbuildOptions: {
        target: "esnext",
    },
},

@hand-dot
Copy link

I also encountered the same error, but I was able to resolve the issue by installing the following vite plugin.
https://www.npmjs.com/package/vite-plugin-top-level-await

@ThisIszas
Copy link

this should be the final answer

{
  build: {
    target: "es2022"
  },
  esbuild: {
    target: "es2022"
  },
  optimizeDeps:{
    esbuildOptions: {
      target: "es2022",
    }
  }
}

@acbellini
Copy link

this should be the final answer

{
  build: {
    target: "es2022"
  },
  esbuild: {
    target: "es2022"
  },
  optimizeDeps:{
    esbuildOptions: {
      target: "es2022",
    }
  }
}

this fixed it for me, thank you!

@Benluc
Copy link

Benluc commented Nov 28, 2023

Is this a solution @jiadesen ?

I'm getting them same as you as jut trying out v4 in a new project and getting:

[watch] build started (change: "js/pdf_preview/index.js")
✘ [ERROR] Top-level await is currently not supported with the "iife" output format

    node_modules/pdfjs-dist/build/pdf.mjs:16837:53:
      16837 │ ...ck_exports__ = globalThis.pdfjsLib = await __webpack_exports__;
            ╵                                         ~~~~~

See https://elixirforum.com/t/importing-pdf-mjs-into-app-js/59578 with --target=es2022 that is via esbuild. If I use the default of --target=es2017 I get:

✘ [ERROR] Top-level await is not available in the configured target environment ("es2017")

    node_modules/pdfjs-dist/build/pdf.mjs:16837:53:
      16837 │ ...ck_exports__ = globalThis.pdfjsLib = await __webpack_exports__;

Should work or should we go back to v3?

I have the same issue here. I am trying to use pdf.js v4 in an elixir/phoenix framework environment where the bundler is esbuild. Should it work or do we have to switch back to v3?

@specialistvlad
Copy link

this should be the final answer

{
  build: {
    target: "es2022"
  },
  esbuild: {
    target: "es2022"
  },
  optimizeDeps:{
    esbuildOptions: {
      target: "es2022",
    }
  }
}

this fixed it for me, thank you!

It works better, compatible with vite-bundle-visualizer

@mturoci
Copy link

mturoci commented Jan 19, 2024

For anyone wanting broader browser support - https://www.npmjs.com/package/vite-plugin-top-level-await.

{
// vite.config
plugins: [
    // ...
    topLevelAwait({
      promiseExportName: '__tla',
      promiseImportName: i => `__tla_${i}`,
    }),
  ],
}

Note: Bundle size will be 30kb larger compared to native es2022.

@farisshomali
Copy link

And if i'm working in Angular project that's been created with Angular CLI (NO VITE CONFIGURATION FILE !), what should i do ?

How to solve this issue with projects that does not based on vite ?

@yuri-apanasik
Copy link

Agree with @farisshomali, angular out-of-the-box uses Webpack, there is possibility to customize its configuration with (experiments: { topLevelAwait: true }), but it means stick to webpack (not good). Trying to use 'esbuild' (planned to be used by Angular out-of-the-box) and pdfjs - build fails ('esbuild' has no intention to support toplevelawait' at all). So, question is can 'top level await' be avoided by 'pdfjs'? It will make it easier to use any bundler.

@yuri-apanasik
Copy link

@Snuffleupagus ↑ ?

@Priestch
Copy link
Contributor

@yuri-apanasik I don't know how you use the pdf.js project, but I think it's possible to avoid use "top level await".

The top level await is used to load the main bundle of pdf.js, it contains all core features any viewer solution will depends on. The pdf.js also has a web bundle, it contains all code the default viewer needs, and of course it depends the main bundle.

The possible way to avoid the top level await is develop a custom gulp task, just build a single bundle which combine the web and main bundles together, then the issue will gone. it's may not be an easy job depending on your knowledge of the pdf.js project.

@yuri-apanasik
Copy link

@Priestch yes, I am new in pdf.js, we just looked for the tool to convert PDF to PNG on the client side and found pdf.js. So, as lazy developers we just took pre-built 'pdfjs-dist' package and faced with bundler issue. For now we are on PoC phase, so as a solution we just downgraded 'pdfjs-dist' to V3. For the production looks like we should go with custom build solution. Thank you for the suggestion!
But at the same time, nowadays it is more common to just 'take and use' and when some package requires complicated setup it looks like something from 90s. Especially when there is no special tooling to apply all configuration with one magical command. It is a joke (partly), but it would be nice if you can provide some examples in the pdfjs docs about custom builds in different cases.

@Priestch
Copy link
Contributor

@yuri-apanasik What do you mean "on the client side"? You used pdf.js in browser or node environment?

If you use it in browser, all you need is comment out two lines code, and run gulp task dist-pre, the result will not contain the top level await.

You can also change the two files to flatten and replace the await __non_webpack_import__ with directly import under some if inNodeJS statement.

libraryAlias["display-node_stream"] = "src/display/node_stream.js";

    // line 305, 306
    // libraryAlias["display-node_stream"] = "src/display/node_stream.js";
    // libraryAlias["display-node_utils"] = "src/display/node_utils.js";

@yuri-apanasik
Copy link

@Priestch I mean in browser, yes. Thank you one more time for the hint! We'll try to make our own pdfjs build. But as you can see it is not only my problem, a lot of developers who want to easily use pre-built package face with this problem. One of the minimal ways to reproduce is:

  • create new Angular app 'ng new app-test-pdfjs-dist'
  • install pdfjs-dist 'npm i pdfjs-dist'
  • add any import 'import { getDocument } from 'pdfjs-dist'' and mention 'getDocument' somehow, so import is not ignored by bundler

Result -> build failed. As you suggested situation can be fixed with custom build, but it makes 'pdfjs' minimal usage example more complicated.
After we fix the issue with custom build we'll probably prepare short blog post, but later, now we are ok with v3 for PoC version.

@jiadesen
Copy link
Author

@Priestch If only in a browser environment, I'd like to know what other code could be annotated and whether this could significantly reduce the size of the build artifact

@Priestch
Copy link
Contributor

@jiadesen it's just quick hack to fix the issue, I think it doesn't reduce the build artifact.

@nicolo-ribaudo
Copy link
Contributor

This seems like a bug in angular, if a default angular app crashes when using a stable JavaScript feature. It's like saying "please don't use classes because Angular has a bug and doesn't support them".

@MikeDabrowski
Copy link

I don't agree this is an issue with Angular. The v3 works for us for now but we had some badly rendered pdfs lately and want an upgrade. The only v3 that worked so far was 3.8.162 due to svg typings issues. We only use basic rendering so never dug deep enough to understand this library. Both builders in angular produce some errors, the common one being this top-level-await. While I understand Angulars position (zone.js etc), I don't know pdf.js enough to understand forcing incompatible builds.

Moreover - there is this legacy build available yet somehow it can't be imported - when building the app it throws not found errors.

We are running out of ideas how to workaround the workaround.

@yuri-apanasik
Copy link

yuri-apanasik commented Feb 1, 2024

@MikeDabrowski if you are using default Angular configuration with Webpack, you can customize it by installing '@angular-builders/custom-webpack' NPM package and changing '@angular-devkit/build-angular' to '@angular-builders/custom-webpack' in angular.json (some more adjustments should be done, just google it). When you can create the following custom webpack config to avoid top-level-await error: module.exports = { experiments: { topLevelAwait: true, }, };.
But as I mentioned earlier that means you somehow stick to webpack and there is no way to switch to 'esbuild' for example. Or, as it was said in the beginning of the issue, if you want 'vite' you need to customize its configuration too.

At the same time @Priestch already suggested the solution with custom 'pdfjs' build.

@nicolo-ribaudo yes, it is NOT angular bug. It is about bundlers, 'esbuild' for example have no intention to support top-level-await at all (evanw/esbuild#253). So, 'pdfjs' in its full version (without commenting out some unnecessary code in case of usage in browser) can't be used with 'esbuild'. 'webpack'/'vite' need custom configuration. So, trying to make an improvement in V4 with es modules (if I got it right) it appeared that developers who used V3 easily now have to spent hours to understand what is wrong with their build using V4...

@MikeDabrowski
Copy link

MikeDabrowski commented Feb 1, 2024

@yuri-apanasik - yep, im just doing it - but v4 changes the location of workers and my app needed them I think. So trying to somehow work that out.

export 'default' (imported as 'pdfjsWorker') was not found in 'pdfjs-dist/build/pdf.worker.mjs' (possible exports: WorkerMessageHandler)

I wouldnt mind that custom build, we could host it. But I dont want to waste time reading how to do it. As you said in one of your comments its like in the 90s -here is kernel, now code build yourself an OS to write play asteroids or sth... Aint nobody got time for that.

Any chance someone posts how to prep whole build?

For reference our usage is for example: - I am not even sure if we need the workers

if (!GlobalWorkerOptions.workerSrc) {
      GlobalWorkerOptions.workerSrc = pdfjsWorker;
    }
    return new Response(file)
      .arrayBuffer()
      .then(
        async (data: BinaryData) =>
          getDocument({ data, verbosity: 0 } as DocumentInitParameters)
            ?.promise,
      )
      .then(async (doc) => {
        const numPages = doc.numPages;
        await doc.destroy();
        return numPages > attachmentPageLimit;
      })
      .catch((e) => {
        if (e.name !== 'PasswordException') {
          throw new Error(e);
        } else {
          throw new JsPdfLibError(this.corruptOrPwdProtectedMessage, e);
        }
      });

@yuri-apanasik
Copy link

@Priestch Just for information... I've tried to make custom pdfjs build, there were some troubles: for example, 'node-canvas' have no arm64 build, so had to solve this issue for M1. Finally pdfjs was ok, but unfortunately when I copied result files into the project and build (actually build was also successful) I faced with error in runtime (some class used before its declaration).
I think it is not 'pdfjs' problem, more likely it is webpack glitches, but with the team we decided not to spend more time on this and stay with 'pdfjs' V3.
I don't believe it is only some people from this issue who faced with 'top level await' incompatibility and didn't upgrade to V4 because of that. So, probably, you can at least discuss in your team this question and measure the necessity of using 'top level await' feature.

@MikeDabrowski
Copy link

Can we get this issue reopened ? This has not been resolved yet.

@yuri-apanasik That is exactly what I was afraid of - more issues when making custom build.

The reason we wanted to update to v4 is that we had one incident with pdf badly rendered - some border was misplaced. Could not reproduce it unfortunately, so now we are waiting and keeping an eye for such errors.

@Priestch
Copy link
Contributor

Priestch commented Feb 7, 2024

@yuri-apanasik If you only use in browser environment, you can safely delete node-canvas from dependencies or optional dependencies list. Other problems may not related to pdf.js, I tested the tricks and I already successfully applied this in real project.

@benbro
Copy link
Contributor

benbro commented Feb 7, 2024

@Priestch can you please show this change?

You can also change the two files to flatten and replace the await non_webpack_import with directly import under some if inNodeJS statement.

HenestrosaDev added a commit to HenestrosaDev/the-wordsmiths-collection that referenced this issue Feb 14, 2024
…evel await is not available in the configured target environment ("chrome87", "edge88", "es2020", "firefox78", "safari14" + 2 overrides)` error [link](mozilla/pdf.js#17245)
@JHarrisGTI
Copy link

JHarrisGTI commented Feb 23, 2024

I'm also struggling with this issue. I upgraded my Angular project to pdf.js v4, struggled with Angular's build system, got it working. Now I'm upgrading Angular from 17.0 to 17.2 and Angular is giving me warnings about using topLevelAwait again.

Angular says they do not support top-level await. That means that developers have to either a) arm-wrestle the Angular compiler into something it's not meant for, b) hack together a custom build of pdf.js as @yuri-apanasik has attempted to do, or c) stay on an old version of pdf.js until that eventually stops working.

I keep solving this issue and then having to re-solve it every time I upgrade a piece of my project. Top-level await has been described in this thread as a "stable JavaScript feature", and that may be true according to the specification, but compiler support for that feature is not yet widespread enough to provide a stable experience. Angular provides two new build systems with v17; neither one supports this feature.

@qstiegler
Copy link

I totally agree with @JHarrisGTI. pdf.js would totally also work without top-level await. Please provide us a version of it which is compatible with the compilers of all big frameworks, including Angular!

@Snuffleupagus
Copy link
Collaborator

Snuffleupagus commented Mar 25, 2024

Note: The reason that we went with top level await in the re-factoring for PDF.js version 4 was to reduce complexity.

It should be possible to remove top level await from the PDF.js builds, and I've even got WIP patches locally.
However doing so would increase code complexity, and thus add to the maintenance burden, of the general PDF.js library and basically cause the (unpaid) core contributors more work.

If you'd like to see top level await be removed from the builds and are serious about paying for that be implemented, please contact me privately. (Email address can be found in my GitHub profile.)


Please keep in mind that the primary development target of this library is the Firefox PDF Viewer, and the fact that the general PDF.js library can still be used elsewhere is thanks to a lot of time/effort spent by a few unpaid contributors (such as myself) over the years.
This is work that no-one is sponsoring and many users don't even bother saying thank you, however a few users seem all too willing to essentially complain about something that's provided for free. For example, comments such as the following seem uncalled for and are quite disheartening to read:

But at the same time, nowadays it is more common to just 'take and use' and when some package requires complicated setup it looks like something from 90s.

@yuri-apanasik
Copy link

@Snuffleupagus as I can see you mentioned my comment, but believe me I had no intention at all to offend you somehow. This is just a visualization how the situation looks like for the person who doesn't know at all the story behind and just is trying to use 'pdfjs' as any other package. I am sure number of downloads and lots of projects where 'pdfjs' is used gives you much more understanding how valuable your work is, than any words. But it will be clear truth (as everything written above) if I will add "Thank you" for you and for all developers who was involved into implementation of this great library that solves for all of as such a complicated thing as working with pdf in browser. Nice to hear there is a chance it will be compatible with 'esbuild', hope complexity growth is not critical.
P.S. If we ever meet each other in person, remember, I owe you a chocolate bar

@wojtekmaj
Copy link
Contributor

@Snuffleupagus I'm definitely interested in having that fixed as a lead maintainer of React-PDF. Please kindly submit $50 expense on https://opencollective.com/react-pdf-wojtekmaj :)

@JHarrisGTI
Copy link

@Snuffleupagus My company is also interested. I emailed you a few days ago but I'm not sure if it went through. Hopefully it didn't get stuck in a spam folder.

@Snuffleupagus
Copy link
Collaborator

@Snuffleupagus My company is also interested. I emailed you a few days ago but I'm not sure if it went through. Hopefully it didn't get stuck in a spam folder.

@JHarrisGTI Thanks, I've replied to the email so let's continue there :-)

@jothbc
Copy link

jothbc commented May 2, 2024

in reactjs using pdfjs-dist (npm) v4.2.67 and vite:

install:

yarn pdfjs-dist;

update vite.config.ts:

  build: {
    target: 'es2022',
  },
  esbuild: {
    target: 'es2022',
  },
  optimizeDeps: {
    esbuildOptions: {
      target: 'es2022',
    },
  },

import:

import * as pdfjsLib from 'pdfjs-dist';

pdfjsLib.GlobalWorkerOptions.workerSrc = '../../node_modules/pdfjs-dist/build/pdf.worker.min.mjs';

my use:

const pdfThumb = await new Promise((resolve, reject) => {
      const fileReader = new FileReader();
      fileReader.onload = async () => {
        try {
          const typedArray = new Uint8Array(fileReader.result as ArrayBuffer);
          const pdf = await pdfjsLib.getDocument(typedArray).promise;
          const page = await pdf.getPage(1);
          const scale = 1.5;
          const viewport = page.getViewport({ scale });
          const canvas = document.createElement('canvas');
          const context = canvas.getContext('2d');
          canvas.width = viewport.width;
          canvas.height = viewport.height;

          const renderContext = {
            canvasContext: context,
            viewport: viewport,
          } as {
            canvasContext: CanvasRenderingContext2D;
            viewport: pdfjsLib.PageViewport;
          };

          await page.render(renderContext).promise;
          const imageUrl = canvas.toDataURL('image/jpeg');
          resolve(imageUrl);
        } catch (err) {
          console.log(err);
          reject('some error');
        }
      };
      fileReader.readAsArrayBuffer(file as FileType);
    });

im my case i only need a thumbnail of pdf...

@Snuffleupagus
Copy link
Collaborator

@JHarrisGTI The PR landed earlier today, and I've tried to reach you (and your colleague) by email; did it get stuck in a spam filter perhaps?

@JHarrisGTI
Copy link

@Snuffleupagus I got your email about the PR yesterday; I believe Adam has emailed you about payment details. I also reached out to our IT department and they say you shouldn't get stuck in the spam filter again. 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.