mozilla / pdf.js

PDF Reader in JavaScript
https://mozilla.github.io/pdf.js/
Apache License 2.0
48.31k stars 9.97k forks source link

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

Closed jiadesen closed 11 months ago

jiadesen commented 11 months ago

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

Configuration:

  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 commented 11 months ago

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 commented 11 months ago

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 commented 11 months ago

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 commented 11 months ago

Searching for the error message Top-level await is currently not supported with the "iife" output format with Google points to https://github.com/evanw/esbuild/issues/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 commented 11 months ago

Solved by adding vite configuration:

optimizeDeps: {
    esbuildOptions: {
        target: "esnext",
    },
},
hand-dot commented 11 months ago

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 commented 11 months ago

this should be the final answer

{
  build: {
    target: "es2022"
  },
  esbuild: {
    target: "es2022"
  },
  optimizeDeps:{
    esbuildOptions: {
      target: "es2022",
    }
  }
}
acbellini commented 11 months ago

this should be the final answer

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

this fixed it for me, thank you!

Benluc commented 10 months ago

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 commented 10 months ago

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 commented 9 months ago

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 commented 8 months ago

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 commented 8 months ago

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 commented 8 months ago

@Snuffleupagus ↑ ?

Priestch commented 8 months ago

@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 commented 8 months ago

@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 commented 8 months ago

@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.

https://github.com/mozilla/pdf.js/blob/833d7ac8303c9002a65911efa6dd4dea4d127db6/gulpfile.mjs#L305

    // line 305, 306
    // libraryAlias["display-node_stream"] = "src/display/node_stream.js";
    // libraryAlias["display-node_utils"] = "src/display/node_utils.js";
yuri-apanasik commented 8 months ago

@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:

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 commented 8 months ago

@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 commented 8 months ago

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

nicolo-ribaudo commented 8 months ago

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 commented 8 months ago

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 commented 8 months ago

@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 (https://github.com/evanw/esbuild/issues/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 commented 8 months ago

@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 commented 8 months ago

@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 commented 8 months ago

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 commented 8 months ago

@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 commented 8 months ago

@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.

JHarrisGTI commented 7 months ago

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 commented 7 months ago

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 commented 6 months ago

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 commented 6 months ago

@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 commented 6 months ago

@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 commented 5 months ago

@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 commented 5 months ago

@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 commented 5 months ago

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 commented 5 months ago

@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 commented 5 months ago

@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. 🙂

Elecash commented 4 months ago

@JHarrisGTI could you throw some light about how to use PDFJS v4.3.136 with Angular?

Elecash commented 4 months ago

I've been able to make it work but I have to set the worker in an external cdn or I have to copy/paste the worker file to /assets.

import * as PDFJS from 'pdfjs-dist';

Promise.all([
            // @ts-ignore: only accepted in commonJs or esNext
            import(/* webpackChunkName: "PDFJS" */ 'pdfjs-dist/build/pdf.min.mjs')
        ]).then(() => {
            PDFJS.GlobalWorkerOptions.workerSrc = 'assets/pdf.worker.min.mjs';
            // Alternatively, load from externalcdn
            // PDFJS.GlobalWorkerOptions.workerSrc = '//unpkg.com/pdfjs-dist@4.3.136/build/pdf.worker.min.mjs';
        });
JHarrisGTI commented 4 months ago

@Elecash Here are some notes I've pulled together from my git commit history over the last few days.

Switch to the legacy build

Since 4.1.392, pdf.js uses Promise.withResolvers; I haven't been able to get that working with any of Angular's build systems. So to get pdf.js 4.3.136 working in Angular, the main thing I've needed to do has been to switch to the legacy build. To do this, replace:

import { whatever } from 'pdfjs-dist'`

with:

import { whatever } from 'pdfjs-dist/legacy/build/pdf.mjs'

That's fixed most of my problems. The builder I'm using is @angular-devkit/build-angular:browser (that goes in angular.json under architect -> build -> builder and architect -> serve -> builder). (With the removal of top-level await I no longer need the custom-webpack builder I'd previously been using. This is great--it brings me closer to the Angular mainstream.)

Worker threads

In cases where I need the performance of a separate worker thread, I add this to the architect -> build -> options -> assets array of angular.json:

{
  "glob": "pdf.worker.min.mjs",
  "input": "./node_modules/pdfjs-dist/legacy/build",
  "output": "./assets"
}

This copies pdf.worker.min.mjs from the node_modules folder into the assets folder of my compiled app. Then, in the place I need the worker:

import * as pdfJsLib from 'pdfjs-dist/legacy/build/pdf.mjs';
pdfJsLib.GlobalWorkerOptions.workerSrc = 'assets/pdf.worker.min.mjs';

const pdf = await pdfJsLib.getDocument({ url }).promise;

Text layers

The renderTextLayer function is deprecated now. Replace:

renderTextLayer({ textContentSource, viewport, container });

with:

new TextLayer({ textContentSource, viewport, container}).render();

And if you're using this library's CSS, the new version sets the z-index of .textLayer to 0. You may want to override that to 1, or whatever fits the rest of your app.

Testing with Jest

I test my app with Jest. Things I did this patch:

Elecash commented 4 months ago

@JHarrisGTI this is very similar to what I did, but thanks for sharing!

MikeDabrowski commented 4 months ago
image

Can we do something about this?

Snuffleupagus commented 4 months ago

image Can we do something about this?

First of all, as a general rule, please always provide log output, error messages, and code as text since it's impossible to e.g. copy and search in an image which makes things more cumbersome. Secondly, what you're asking about seems pretty orthogonal to this issue which was about top level await (and that's been fixed).

@MikeDabrowski If we attempt to work-around your issue, in the way the error message suggests, are you willing to sponsor me for writing the patch?

MikeDabrowski commented 4 months ago

@Snuffleupagus I meant 'we' as we the end users of this library. Sorry for the screenshot, here's the text

Application bundle generation complete. [1.561 seconds]
Watch mode enabled. Watching for file changes...
NOTE: Raw file sizes do not reflect development server per-request transformations.
  ➜  Local:   http://localhost:4200/
  ➜  press h + enter to show help
4:00:05 PM [vite] warning: 
/Users/mike/IdeaProjects/my-project/.angular/cache/18.0.3/vite/deps/pdfjs-dist_legacy_build_pdf__mjs.js
15695|          const worker = yield import(
15696|            /*webpackIgnore: true*/
15697|            this.workerSrc
   |            ^^^^^^^^^^^^^^
15698|          );
15699|          return worker.WorkerMessageHandler;
The above dynamic import cannot be analyzed by Vite.
See https://github.com/rollup/plugins/tree/master/packages/dynamic-import-vars#limitations for supported dynamic import formats. If this is intended to be left as-is, you can use the /* @vite-ignore */ comment inside the import() call to suppress this warning.
  Plugin: vite:import-analysis
  File: /Users/mike/IdeaProjects/my-project/.angular/cache/18.0.3/vite/deps/pdfjs-dist_legacy_build_pdf__mjs.js?v=c9270bac
No output file changes.

Are you certain that this warning was not caused by the work that was recently carried out here to enable the library in latest Angular?

Maybe I am the only one affected and maybe only my setup is broken.

Viet47 commented 4 months ago

Same problem, Esbuild of angular doesn't support dynamic-import of webpack

JHarrisGTI commented 4 months ago

I see the same problem @MikeDabrowski reports when I try to use browser-esbuild, Angular's new Vite-based build system, so for now I am avoiding that system and sticking with the browser build system. That's not much help to people who are starting new Angular apps, which use browser-esbuild by default.

Unrelated to Angular, to make the new version work in my NestJS backend, here's what I changed in tsconfig.json:

{
  "compilerOptions": {
    "module": "Node16",
    "moduleResolution": "Node16",
  }
}
malek-itani commented 3 months ago

this worked for me, using angular@18 & pdfjs-dist@4

package.json

  "dependencies": {
    "@angular/animations": "^18.0.0",
    "@angular/common": "^18.0.0",
    "@angular/compiler": "^18.0.0",
    "@angular/core": "^18.0.0",
    "@angular/forms": "^18.0.0",
    "@angular/platform-browser": "^18.0.0",
    "@angular/router": "^18.0.0",
    "pdfjs-dist": "^4.4.168",
    "rxjs": "^7.8.1",
    "tslib": "^2.5.0",
    "zone.js": "~0.14.0"
  },

PDF Render Component

import { Component, ElementRef, ViewChild } from '@angular/core';
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf.mjs';
import 'pdfjs-dist/webpack';
import { PDF_BASE64 } from '../utils/pdf-base64';

@Component({
  selector: 'app-pdf-render',
  standalone: true,
  template: `
    <p>My PDF:</p>
    <p>
      <canvas #myCanvas></canvas>
    </p>
  `,
})
export class PDFrender {
  @ViewChild('myCanvas', { static: false }) canvas!: ElementRef;

  constructor() {
    // you can use direct URL to file
    var url =
      'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/examples/learning/helloworld.pdf';

    // OR you can use PDF as Base64-encoded data
    let pdfData = atob(PDF_BASE64);
    console.log(pdfjsLib.version);
    //
    // The workerSrc property shall be specified.
    //
    pdfjsLib.GlobalWorkerOptions.workerSrc = `//cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjsLib.version}/build/pdf.worker.mjs`;
    //
    // Asynchronous download PDF
    //
    var loadingTask = pdfjsLib.getDocument({ data: pdfData });
    loadingTask.promise.then((pdf) => {
      //
      // Fetch the first page
      //
      pdf.getPage(1).then((page) => {
        var scale = 1.5;
        var viewport = page.getViewport({ scale: scale });

        //
        // Prepare canvas using PDF page dimensions
        //
        var context = this.canvas.nativeElement.getContext('2d');
        this.canvas.nativeElement.height = viewport.height;
        this.canvas.nativeElement.width = viewport.width;

        //
        // Render PDF page into canvas context
        //
        var renderContext = {
          canvasContext: context,
          viewport: viewport,
        };
        page.render(renderContext);
      });
    });
  }
}

thanks to JHarrisGTI for pointing out how to use the legacy import.

MikeDabrowski commented 3 months ago

@JHarrisGTI

pdfJsLib.GlobalWorkerOptions.workerSrc = 'assets/pdf.worker.min.mjs';

I did that too, my deployed assets contain the worker file but the src like that cant use it.

Error: Setting up fake worker failed: "Failed to resolve module specifier 'assets/pdf.worker.min.mjs'"

Have you seen such error?

Even if I put the full url to this file - the error is Failed to fetch dynamically imported module

JHarrisGTI commented 3 months ago

@MikeDabrowski I have not seen such an error. ☹️ If pdf.worker.min.mjs is in your assets folder, I don't know why pdf.js would be unable to see it. Sorry I can't be more help.