ArtifexSoftware/mupdf.js

mupdf.js library doesn't work on zoneless Angular

Opened this issue · 3 comments

I attempted to use the mupdf.js library in Angular.

Repo link: MuPDF.js Angular Demo
First, I reviewed the Angular demo in the repository.

Reference: mupdf.worker.ts (lines 24-34)
The demo uses a mupdf variable to dynamically import the mupdf.js script because Angular 18.0 doesn't support top-level await.

The reason Angular doesn't support top-level await is due to zone.js. (Reference)
However, starting from Angular v18.1, top-level await is supported only in a zoneless environment. (18.0 Release Notes / 18.1 Release Notes)

I then attempted to use the mupdf.js library in a zoneless Angular environment.
Here is a minimal reproduction: MuPDF Angular Example
However, it did not work.

Steps to Reproduce

1. ng serve

npm ci
npm start

The application starts successfully, but if you check the network tab, you'll see that mupdf-wasm.wasm is not being loaded. (I think Content-Type: text/html is problem?)

2. ng build

npm run build

The build fails with the following error:

Application bundle generation failed. [1.429 seconds]

✘ [ERROR] Could not resolve "module" [plugin angular-compiler]

    node_modules/mupdf/dist/mupdf-wasm.js:100:41:
      100const { createRequire } = await import('module');
          ╵                                          ~~~~~~~~

  The package "module" wasn't found on the file system but is built into node. Are you trying to bundle for node? You can use "platform: 'node'" to do that, which will remove this error.

Question

Is there a solution for this issue? Or should I follow the approach used in the repository's demo?

If I missed anything, please let me know.
Thank you!

There are many problems with bundlers not able to "compile" the Emscripten generated code.

We always recommend using MuPDF WASM library via a WebWorker, to avoid blocking the main UI thread.

When using MuPDF.js from a WebWorker, you do not need to use the bundler to compile the web worker and MuPDF.js modules. See the "simple-viewer" example for a minimal WebWorker implementation.

I understand. Could you confirm if my understanding is correct?

import * as mupdf from "./mupdf.js"

/* ... */

I’ve been using mupdf.js as you described. I built mupdf.js directly and imported it in mupdf-worker.js, and everything has been working fine.

However, I recently checked the mupdf.js library on NPM and noticed that the build result includes mupdf.d.ts. This made me think I could use mupdf.js with the NPM package and TypeScript. So, I tried the steps mentioned above.

From what you’re saying, to use mupdf.js in the browser, I shouldn’t use the NPM library. Instead, I should continue using the build result from mupdf.js, as I did before. Is that correct?

+ In addition, my issue is a compile failure in mupdf-wasm.js, and that compile error seems difficult to resolve because mupdf-wasm.js is created by Emscripten. So, I should use mupdf.js the way it’s done in the simple-viewer example. Is that right?

The files in the NPM package "dist" should be identical to the ones you get by building it yourself.

The mupdf.d.ts file contains type definitions if you want to use MuPDF.js from TypeScript.

Using TypeScript and using the NPM distributed build have nothing to do with each other: you can do one or the other or both or neither.