Menci / vite-plugin-wasm

Add WebAssembly ESM integration (aka. Webpack's `asyncWebAssembly`) to Vite and support `wasm-pack` generated modules.
MIT License
281 stars 16 forks source link

404 fetching '.wasm' #40

Closed inzanez closed 9 months ago

inzanez commented 11 months ago

Hi

I just tried using Sveltekit && Vite4 to import a module built with wasm-pack using wasm-pack build --target web. I installed the package in my test-project, and added topLevelAwait and wasm.

In my project, I import init, {my_test_function} from 'wasm-test-package';. Running the dev build, this leads to:

http://localhost:5173/node_modules/.vite/deps/wasm-test_bg.wasm --> 404 Not found.

Interestingly, the production build published and served via web-browser does not have any issues and loads the wasm file.

inzanez commented 11 months ago

Ok, I just read another issue where it sais to use --target bundler, which I just did. But now my import does not work anymore:

SyntaxError: The requested module '/node_modules/.vite/deps/wasm-test.js?t=1695209278974&v=543b7d03' does not provide an export named 'default' (at...

inzanez commented 11 months ago

Ok, and finally got it working, by just removing the init import. Just for my understanding: I used to await init, now init does not exist anymore, but it seems I can call my_test_function nevertheless. No need for init anymore then?

bucko13 commented 11 months ago

I'm also seeing this. If I don't use await init() then there will be errors from the wasm-pack generated code from the wasm not being loaded. With the await init() I get a 404. The reason for the 404 comes from generated code that looks like this:

async function __wbg_init(input) {
    if (wasm !== undefined) return wasm;

    if (typeof input === 'undefined') {
        input = new URL('your_module.wasm', import.meta.url);
    }
    const imports = __wbg_get_imports();

    if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
        input = fetch(input);
    }

    __wbg_init_memory(imports);

    const { instance, module } = await __wbg_load(await input, imports);

    return __wbg_finalize_init(instance, module);
}

specifically the place where input gets set if it's none. The url that gets set is something likenode_modules/.vite/deps/your_module.wasm`.

In my case, this does exist in the built code (a js/ts library that uses wasm) but only the .js files end up getting pulled in to deps.

I tried adding assetsInclude: ["**/*.wasm"], to the config but that didn't seem to get it into the .vite/deps directory. Something that might be related is that this is a library that's being developed locally and installed via file path to the consuming vite project. So I added the package in question to include in optimizeDeps.

If I manually copy the wasm into the .vite/deps directory then it works.

inzanez commented 11 months ago

@bucko13 I just tried the same with having the project published to NPM and installed as a package, not having it local. That doesn't make no difference.

bucko13 commented 11 months ago

So I managed to fix this with a workaround based on this discussion in the main vite project, basically by excluding from dependency optimization the package being imported that had wasm.

Menci commented 9 months ago

There should NOT be an init() in bundler mode of wasm-pack.

Note that it should work without the dependency optimization exclusion workaround. Reopen this if there's any issue non-related to init().

bucko13 commented 9 months ago

It’s been a while since I was playing around with this and managed to get it working with the above workaround, but I think part of the issue is that if I needed to work on package locally and test it out as a dependency of a vite project, then the exclusion is necessary. And as noted, without the init then the wasm isn’t loaded. So the two steps work together: exclude from dependency optimization to include the wasm, init to load it.