Menci / vite-plugin-wasm

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

SSR support #4

Closed boyeln closed 1 year ago

boyeln commented 2 years ago

Currently the wasmHelper code tries to load the wasm file through fetch. This only works in a browser context. Even if fetch were available, fetching a relative path would still not work. I believe it should be fairly easy to get it working in a server context as well. One easy fix would be to add an else if clause in the wasmHelper function:

const wasmHelper = async (opts = {}, url: string) => {
  let result: WebAssembly.WebAssemblyInstantiatedSource;
  if (url.startsWith("data:")) {
    // Existing base64 case
  else if (isServer()) {
    // New server case. Wasm file should be loaded from file system.
  } else {
    // Existing fetch case
  }
  return result.instance.exports;
};

The isServer check could be as simple as typeof window === "undefined". However, I could see cases where this would be problematic. Some might have other vite plugins that polyfills window for server contexts etc. Another approach might be to use import.meta.url, and see if it refers to a URL or a file, e.g. import.meta.url.startsWith("file:"). I'm not sure if this would always work, or if it might come with some gotchas.

Are you open to a PR that implements something like this?

boyeln commented 2 years ago

Just realized that import.meta.url would only work for ESM, so I guess we have to use some sort of typeof window, typeof process etc.

boyeln commented 2 years ago

Perhaps another approach might be to just try the fetch, then catch and see if it's an "ERR_INVALID_URL" error. If it is, we could try loading it from the file system.

Menci commented 2 years ago

I don't use Vite SSR. But I see in Vite's docs there's an environment variable to tell if it's on server or client: https://vitejs.dev/guide/ssr.html#conditional-logic.

Could you open a PR and send an example project for me(since I never used SSR)? Thanks. Additionally, this code is from Vite's builtin WASM plugin, you may also create a PR for that.

boyeln commented 2 years ago

Yeah, might be worth while to create a PR there as well. However, regarding the import.meta.env.SSR, I belive that would only work if you bundled your plugin as ESM. It's a small change, but you might have use cases that requires CJS?

Menci commented 2 years ago

Could you please provide a simple WASM+SSR project, which works without SSR, for me to implement SSR support?

boyeln commented 2 years ago

Here's a simple example using SvelteKit. Just start the dev server and navigate to the SSR page. Everything works as expected if you apply the patch (npx patch-package). I have never implemented SSR with vite using anything other that SvelteKit unfortunately.

Menci commented 2 years ago

You have the directory patches and have no patch-package package in your project ...

Menci commented 2 years ago

It seems that vite-plugin-top-level-await is not compatible with your example project. I'll investigate into this issue later.

mkermani144 commented 2 years ago

I encountered the same issue when I tried to use vite-plugin-wasm with vitest. Because vitest runs in Node, the same issues with fetch happens.

rossng commented 2 years ago

I have created #16 with a patch that enabled me to get vite-plugin-wasm working in Vitest. Would be very useful to get some feedback on this approach so I can decide whether to commit time to writing some proper tests for it.

boyeln commented 1 year ago

Just open sourced our vite wasm plugin with SSR support. It's only tested on our use case in our environment, so it probably has tons of gotchas and issues. Perhaps it could be used as inspiration if you choose to add SSR support.

Menci commented 1 year ago

Added SSR support in v3.2.0. Please test~

rossng commented 1 year ago

I swapped out my hacky fork for v3.2.1 and it appears to work!

Really appreciate your work on this plugin @Menci