Skip to content

Conversation

@upsuper
Copy link

@upsuper upsuper commented Nov 10, 2025

This PR intends to add WASM support for Vitest and SSR. It should fix #8882 as well as vitest-dev/vitest#6723.

Implementation

The main changes are in the wasm plugin, that provide different helper code based on whether the consumer is server or client. As I'm new to this project, it's not clear to me whether this is the right approach.

I also looked into vite-plugin-wasm for how it handles SSR and vitest. What it does is:

  • explicitly detect whether it's under SSR or whether it's running for Vitest, and
  • if so, force inline WASM into base64 encoded form.

This approach doesn't feel great to me.

Testing

There are two tests I added:

  • A new e2e test ssr-wasm which serves SSR with WASM loaded.
  • New tests inside existing wasm e2e test that checks that WASM can be imported and run within tests.

It's not clear to me whether those tests are in the right location. Please let me know if there are better places for them.

Regarding Vitest

Checking consumer actually doesn't seem to be a reliable way to work in Vitest. Vitest's environment can specify viteEnvironment. Within its builtin environments, jsdom and happy-dom specifies client as their vite environment which, on the Vite side, uses consumer: 'client', even though the tests are still running in Node.js.

I'm going to leave it there given that Vitest's default environment is node, so this mechanism should just work most of the time, and also because I failed to find a way to add test for this behavior.

I tried adding // @vitest-environment jsdom to a spec file, but esbuild complains about

Invariant violation: "new TextEncoder().encode("") instanceof Uint8Array" is incorrectly false

which is probably because jsdom doesn't have the proper implementation for it currently. So I'm not going to dig deeper on this rabbit hole for now.

One trick I found is that some plugins like vite-plugin-solid implicitly changes the test environment, which could potentially cause confusion.

If someone wants to address this part in the future, one possible approach is from vite-plugin-wasm that goes through plugins to find vitest, then combine it with the consumer check to decide which way the file is passed and obtained. It's hacky but I can confirm it works locally.

@upsuper upsuper changed the title Add wasm support for test and SSR feat: Add wasm support for test and SSR Nov 10, 2025
@upsuper upsuper changed the title feat: Add wasm support for test and SSR feat: add wasm support for test and SSR Nov 10, 2025
Copy link
Member

@sapphi-red sapphi-red left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, but this isn't working for build.
When I run vite build --ssr src/app.js in playground/ssr-wasm, I expect the wasm files to be copied (or inlined depending on the option) to dist. But that didn't happen.

@sapphi-red sapphi-red added p2-nice-to-have Not breaking anything but nice to have (priority) feat: ssr feat: wasm labels Nov 11, 2025
@upsuper upsuper requested a review from sapphi-red November 12, 2025 02:07
return result
}
}
if (relative && !ssr) {
Copy link
Author

@upsuper upsuper Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to admit I have no idea why this condition was written this way before. I can see it was initially added in #8762 but couldn't figure out why it was there. Changing this also doesn't seem to fail any test, so I suppose it isn't very critical.

I think it makes more sense for SSR to always use relative path for building. While client code can use either absolute path or relative path, server code almost definitely need relative path, since files have to be accessed through filesystem rather than network request, and the current directory the process starts from is often not reliable for resolving paths.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is to generate the same path in both client build and SSR build. That is the expected behavior by meta-frameworks. The failure in the downstream project looks like this: https://github.com/vitejs/vite-ecosystem-ci/actions/runs/19456693621/job/55671884733#step:7:508

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. This is quite challenging. There are three potential solutions I have in mind:

  • Only use relative if ssrEmitAssets is set.
  • Only use relative if the file is a .wasm file.
  • A combination of both (use relative if both emitting is enabled and the file is a .wasm file).

The main conflict here is probably that WebAssembly files, while can be considered as assets given they are binary files, also involve in computation, unlike most other assets where the code really just need a reference to pass to the browser.

That being said, there could still be cases where ssr code wants to read from assets, for example, a page that renders background color based on an image asset. Those are probably more edge cases, though.

I'm leaning towards the first option so that we don't treat wasm too specially, and if one decides that ssr should emit assets, it could be a good signal that the code may want to read from it rather than just passing a reference to browser.

WDYT? Do you have any other options in mind?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, some meta-frameworks uses ssrEmitAssets: false to avoid processing the assets twice while expecting the URL to reference the asset's URL (which I think needs to be fixed in the future though).

I think we need to treat this PR's case specially for now. We need to keep the normal wasm asset URLs as-is for compatibility.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By “if ssrEmitAssets is set”, I mean ssrEmitAssets === true, since otherwise the wasm file wouldn't even present.

I can look into treating it specially and see how it goes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By “if ssrEmitAssets is set”, I mean ssrEmitAssets === true, since otherwise the wasm file wouldn't even present.

Some meta-frameworks uses ssrEmitAssets: true, so that doesn't work as well.

@upsuper
Copy link
Author

upsuper commented Nov 12, 2025

@sapphi-red Thanks for your review! I have looked into the issue, and now build should be working correctly.

The test should now be covering the build case properly as well, and I've add some tests to verify the build result. Also I have done some manual testing locally and confirmed that it works the way I'd expect.

@upsuper
Copy link
Author

upsuper commented Nov 17, 2025

Hi @sapphi-red, it has been a week since the last update of this PR, would you mind taking another look at it? Is there anything I can do to help moving it forward?

@sapphi-red
Copy link
Member

/ecosystem-ci run

@pkg-pr-new
Copy link

pkg-pr-new bot commented Nov 18, 2025

Open in StackBlitz

npm i https://pkg.pr.new/vite@21102

commit: 11375b1

@vite-ecosystem-ci
Copy link

📝 Ran ecosystem CI on bccd855: Open

suite result latest scheduled
astro failure failure
analogjs failure failure
marko failure success
vite-plugin-cloudflare failure failure
unocss success failure
storybook failure failure
sveltekit failure success
qwik failure failure
react-router ⏹️ cancelled ⏹️ cancelled
vite-plugin-rsc failure success
vike failure failure
one failure failure
waku failure success
vuepress failure success

histoire, ladle, vite-environment-examples, vite-plugin-react, quasar, vite-plugin-svelte, vite-plugin-pwa, vitest, vitepress, vite-setup-catalogue, rakkas, vite-plugin-vue, nuxt, laravel

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

Labels

feat: ssr feat: wasm p2-nice-to-have Not breaking anything but nice to have (priority) trigger: preview

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support wasm in SSR

2 participants