vivliostyle / vivliostyle.js

📖 The power of CSS typesetting, right at your fingertips.
https://vivliostyle.org
GNU Affero General Public License v3.0
601 stars 52 forks source link

Support WebAssambly #1377

Open mogoh opened 2 weeks ago

mogoh commented 2 weeks ago

Is your feature request related to a problem? Please describe.

Some tools that I have are created in rust compiled to wasm. This are front-end tools that are used to render content, that are relevant for PDF generation.

Describe the solution you'd like

Please support WebAssambly. This should not result in an empty PDF:

vivliostyle build https://wasmbyexample.dev/examples/hello-world/demo/rust/ --log-level verbose -s A4 -o wasm-hello-world.pdf

Describe alternatives you've considered

The alternative is to completely avoid wasm and everything that compiles to it.

I must admit, that this is not very high priority to me. It would be nice to have though.

MurakamiShinyu commented 3 days ago

I investigated the issue and found that the problem is not related to WebAssembly support.

Your example:

vivliostyle build https://wasmbyexample.dev/examples/hello-world/demo/rust/ --log-level verbose -s A4 -o wasm-hello-world.pdf

To investigate the problem, I used vivliostyle preview insted of vivliostyle build so that I can debug using browser's DevTools.

vivliostyle preview https://wasmbyexample.dev/examples/hello-world/demo/rust/

I found that the WASM file "./pkg/hello_world_bg.wasm" is failed to load because the relative URL is wrongly resolved against the location of Vivliostyle Viewer which the vivliostyle preview command opens.

This can be fixed by using absolute URL, e.g. "https://wasmbyexample.dev/examples/hello-world/demo/rust/pkg/hello_world_bg.wasm", or by using the URL of the currently running script as the base URL to resolve the relative URL.

Try the following fixed code:

index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World</title>
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="result"></div>
  </body>
</html>

index.js:

import wasmInit from "./pkg/hello_world.js";

const runWasm = async () => {
  const helloWorld = await wasmInit(new URL("./pkg/hello_world_bg.wasm", import.meta.url));

  const addResult = helloWorld.add(24, 24);

  document.getElementById('result').textContent = `Hello World! addResult: ${addResult}`;
};
runWasm();

Note that the import.meta.url is used to get the URL of the running script (module) as the base URL to resolve the relative URL. Also note that the document.getElementById('result').textContent = … is used instead of document.body.textContent = … because the document.body is the body element of the Vivliostyle Viewer, and replacing its content breaks the viewer.