Skip to content
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

Support wasm in SSR #8882

Open
4 tasks done
boyeln opened this issue Jul 1, 2022 · 5 comments
Open
4 tasks done

Support wasm in SSR #8882

boyeln opened this issue Jul 1, 2022 · 5 comments

Comments

@boyeln
Copy link

boyeln commented Jul 1, 2022

Description

Currently, the wasm plugin usually get the .wasm file using fetch. This approach doesn't work in SSR. Even if fetch were available, fetching a relative path would not work. This results in errors such as ERR_INVALID_URL when in SSR.

Suggested solution

By adding an extra if cause to the wasm helper, we could check the import.meta.env.SSR to see if we're in SSR mode. If we are, then we could load the file from disk instead of fetching it over the network. Something like this:

const wasmHelper = async (opts = {}, url: string) => {
  if (url.startsWith('data:')) {
    // load from inline base64 string
  } else if (import.meta.env.SSR) {
    // load from disk
  } else {
    // fetch over the network
  }
}

However, there might be problems to using import.meta that I'm not aware of. It seems to work fine for me when I'm testing it, but I've only tested it with SvelteKit.

If using the SSR environment variable isn't an option, then we could of course use some typeof window === "undefined" or perhaps process would be better. But there might be several pitfalls with that, mainly other plugins that polyfills window, process or whatever thing we might use. Perhaps a better approach would be to add the file system logic in a .catch block on the fetch itself, something like:

const response = await fetch(url).catch(async (err) => {
  if (!(err && err.code === "ERR_INVALID_URL")) throw err;
  // load from disk and return new Response(fileBuffer)
}

Another problem with loading from disk is that the URL provided is a URL, and not a file path. Fortunately it contains the file path, but I'm not sure if that would always be the case, or if it might be a better way of resolving the file path. Using the provided url string, it is possible to decode the path using something like url.replace("/@fs", "").

Alternative

A workaround is to use another wasm plugin. I haven't found a vite wasm plugin that works with SSR, so currently we have created our own just to make it work (using the import.meta.env.SSR technique mentioned above). That works great with SvelteKit, but might not work with everything. If it's of any interest to someone else, just let me know and I can see if we could push it to NPM.

I've also raised an issue (Menci/vite-plugin-wasm#4) in the vite-pugin-wasm repo to make SSR work, but it has some challenges regarding ESM to utilize import.meta.

Additional context

No response

Validations

@boyeln
Copy link
Author

boyeln commented Jan 9, 2023

If anyone finds this issue and needs a quick fix, we've created a vite plugin to use your WASM packages as regular ES modules that also supports SSR. Only supports wasm-pack generated modules at the moment.

@elalish
Copy link

elalish commented May 10, 2024

I found this issue because I was trying to understand a regression I found that's blocking me updating from Vite 4.5.0 to Vite 5.2.11. I have a WASM library I built as an ES module with Emscripten, so I have manifold.js and manifold.wasm in my built directory. In a worker I call it like import Module from './built/manifold';

In Vite 4 this was working just fine both in the browser and in my node-based testing with npm test (what I believe you're referring to as SSR). In Vite 5, everything in the browser still works just fine, but npm test gives:

stderr | worker.test.js > Examples > Rounded Frame
TypeError: Invalid URL
    at new URL (node:internal/url:787:36)
    at Module.default (/Users/elalish/Code/manifold/bindings/wasm/examples/built/manifold.js:8:20330)
    at /Users/elalish/Code/manifold/bindings/wasm/examples/worker.ts:17:16
    at InlineWorkerRunner.runModule (file:///Users/elalish/Code/manifold/bindings/wasm/examples/node_modules/vite-node/dist/client.mjs:362:5)
    at InlineWorkerRunner.directRequest (file:///Users/elalish/Code/manifold/bindings/wasm/examples/node_modules/vite-node/dist/client.mjs:346:5)
    at InlineWorkerRunner.cachedRequest (file:///Users/elalish/Code/manifold/bindings/wasm/examples/node_modules/vite-node/dist/client.mjs:189:14)
    at InlineWorkerRunner.executeFile (file:///Users/elalish/Code/manifold/bindings/wasm/examples/node_modules/vite-node/dist/client.mjs:161:12) {
  code: 'ERR_INVALID_URL',
  input: '/built/manifold.wasm'
}

So even though manifold.js is calling manifold.wasm in its own directory, it can't seem to resolve the URL. But this used to work, which makes me wonder if it's actually related to this issue after all. I don't see anything obviously related in the Vite 5 migration guide. Any thoughts?

Also, the Vite docs seem to say a lot about needing plugins for loading WASM, but I'm not using any plugins with Vite 4. Has functionality been removed from core?

@hi-ogawa
Copy link
Collaborator

in my node-based testing with npm test (what I believe you're referring to as SSR)

@elalish from the error message, it looks like you're referring to Vitest with @vitest/web-worker and that's way more moving parts than just Vite SSR. Can you report on Vitest with https://github.com/vitest-dev/vitest with a reproduction? It's also possible that you're getting a new error due to some change on Vitest.

@elalish
Copy link

elalish commented May 10, 2024

Ah, correct you are! Okay, Vite 5.2.11 is working fine - it must have been the Vitest update that did it. I'll report over there instead - had sort of thought that was all part of the same project.

@elalish
Copy link

elalish commented May 11, 2024

Done: vitest-dev/vitest#5704

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

No branches or pull requests

5 participants