Skip to content

Target no-modules failed to find its .wasm file automatically #2502

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

Closed
yume-chan opened this issue Mar 18, 2021 · 2 comments · Fixed by #3169
Closed

Target no-modules failed to find its .wasm file automatically #2502

yume-chan opened this issue Mar 18, 2021 · 2 comments · Fixed by #3169
Labels

Comments

@yume-chan
Copy link
Contributor

Describe the Bug

When building with --target no-modules, the output js file should be able to find its .wasm file.

Steps to Reproduce

  1. Clone the without-a-bundler-no-modules example and build
  2. Modify index.html as:
    - await wasm_bindgen('./pkg/without_a_bundler_no_modules_bg.wasm');
    + await wasm_bindgen();
  3. Open it in a browser (I'm using Microsoft Edge 89.0.774.54)

Expected Behavior

It loads the .wasm file and runs.

Actual Behavior

Uncaught (in promise) CompileError: WebAssembly.instantiate(): expected magic word 00 61 73 6d, found 3c 68 74 6d @+0

Additional Context

I treat it as a bug because the generated code did try to detect the correct url for its .wasm file, but it failed.

Related code:

    async function init(input) {
        if (typeof input === 'undefined') {
            let src;
            if (typeof document === 'undefined') {
                src = location.href;
            } else {
                src = document.currentScript.src;
            }
            input = src.replace(/\.js$/, '_bg.wasm');
        }
//...

The problem is that, document.currentScript refers to the current processing script, so as most of time init was been called from another script (and in this case, a script tag without src), this code fails.

The correct method is caching document.currentScript.src when it's initializing, for example:

+     const cachedSrc = document.currentScript.src;
      async function init(input) {
          if (typeof input === 'undefined') {
              let src;
              if (typeof document === 'undefined') {
                  src = location.href;
              } else {
-                 src = document.currentScript.src;
+                 src = cachedSrc;
            }
            input = src.replace(/\.js$/, '_bg.wasm');
        }

I verified it works after the modification:

image

@yume-chan yume-chan added the bug label Mar 18, 2021
@ghost
Copy link

ghost commented Apr 7, 2021

We can't literally cache it like you had shown, because the code needs to check for the existence of the document object.

What we can do instead is cache the entire expression.

If document doesn't exist, and is created later, then I doubt that we'd want that document object, and the location won't change without reloading the scripts, so the entire thing can be a constant.

const cached_source = ("document" in globalThis
    ? document.currentScript.src
    : location.href
).replace(/\.js$/, "_bg.wasm");

async function init(input = cached_source) {
    ...
}

@ghost
Copy link

ghost commented Apr 8, 2021

I would like to create a small PR updating both, ESM and non-ESM to cache the default sources so they will have equal performance at runtime, but I'd like to know, in what cases is it expected that the client would have a location, but not a document?

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

Successfully merging a pull request may close this issue.

1 participant