gbj opened issue #5557:
Feature
#3937 contains a good discussion of the problems encountered when trying to compile a program that has any
wasm-bindgen
dependencies in a WASI environment. However, this has significant effects on the ability to usewasmtime
, or any environments that usewasmtime
, to render HTML for apps created in any of the common Rust frontend frameworks. This is because virtually the whole Rust web ecosystem includingweb-sys
andjs-sys
depend onwasm-bindgen
, and they are the building blocks for all the Rust frontend web frameworks. For example, it's very common fIf you are building a native server binary, these
wasm-bindgen
ecosystem libraries compile fine, but panic if you try to run them, for obvious reasons — you are not running in the browser, so do not have access to web APIs. Frameworks are built to handle this. For example, it's very common to declare an HTML element event listener that depends on one of theweb_sys::Event
types. This can be compiled into a native server binary; it simply won't ever be run on the server, so it does not cause an issue.However, attempting to do the same in
wasmtime
causes the error in the issue linked above. See e.g., https://github.com/leptos-rs/leptos/issues/295Benefit
This would allow people to use
wasmtime
for server-side rendering in frameworks like Yew, Sycamore, Leptos, etc. that depend onweb-sys
andwasm-bindgen
, just as they can use native binaries for that same task.Implementation
I don't know enough about how
wasm-bindgen
works internally to make a real proposal, but given that none of thewasm-bindgen
code actually needs to run, it seems that the "allow it to compile and panic if called" solution used for building native binaries for other platforms should work just as well. I'm sure the fact that this seems straightforward is a testament to my own ignorance, here, so apologies.Alternatives
I've laid out a couple alternative approaches for users to this kind of issue in my reply to the issue in the Leptos repo (https://github.com/leptos-rs/leptos/issues/295)
- Leptos mocks and reexports most of
web-sys
, in a way that usesweb-sys
on the client and stubs on the server. Significant maintenance burden for the framework.- Leptos adds a wasi feature. Opting into it means you lose
web-sys
types for this and need to do something like#[cfg(not(feature = "wasi"))]
on all your event listeners and other code that needs platform types. Significant burden on library users.- Use a Wasm-based serverless platform like Cloudflare Workers that's built on V8, so does support wasm-bindgen.
- Use a platform that lets you deploy native binaries so you can build on top of an Actix or Axum server to serve your app.
alexcrichton commented on issue #5557:
Thanks for the report! I definitely agree that the widespread use of
wasm-bindgen
clashes with Wasmtime and out-of-browser environments. As one of the primary authors ofwasm-bindgen
, however, I don't think that this would be a good idea."Support
wasm-bindgen
outside of a browser" would basically involve:
- Hard-code
wasm-bindgen
's bespoke, nonstandard, and project-specific method of binding to web APIs. This is highly dependent on thewasm-bindgen
crate version and changes over time, there's no stability here.- Implement all browser APIs in Wasmtime, natively. Naturally this is a sisyphean task for not really all that much benefit, for example what does it mean to create a DOM node in an out-of-browser environment?
Neither of these fundamental pillars of supporting
wasm-bindgen
make sense to implement in Wasmtime, in my opinion.Again though I don't disagree that there's pain here in mixing browser and out-of-browser environment but I don't believe unifying the environments is a solution. Instead I think it would be better to be clearer and more consistent about what code compiles where and where it runs. This is also a very difficult question and isn't necessarily all that much easier than the above, but it's more scalable into the future I believe.
gbj commented on issue #5557:
To be clear I agree that it would be a very bad idea to try to implement the browser APIs. The behavior I'd expect is the behavior on any other target: the code compiles and runs but if I actually try to call a wasm-bindgen function it panics. I guess I don't understand why this is possible for arbitrary native targets but not WASI, but again, I'm sure that's my own ignorance.
gbj commented on issue #5557:
Just to expand with a very simple example:
fn get_window() -> Option<web_sys::Window> { web_sys::window() } fn main() { if false { get_window(); } println!("Hello, world!"); }
If I
cargo run
this, it compiles and runs, printingHello, world!
.If I
cargo build --target wasm32-wasi && wasmtime target/wasm32-wasi/debug/wasmtimeexample.wasm
, it compiles and then the expected runtime errorError: failed to run main module `target/wasm32-wasi/debug/wasmtimeexample.wasm` Caused by: 0: failed to instantiate "target/wasm32-wasi/debug/wasmtimeexample.wasm" 1: unknown import: `__wbindgen_placeholder__::__wbindgen_describe` has not been defined
gbj edited a comment on issue #5557:
Just to expand with a very simple example:
fn get_window() -> Option<web_sys::Window> { web_sys::window() } fn main() { if false { get_window(); } println!("Hello, world!"); }
If I
cargo run
this, it compiles and runs, printingHello, world!
.get_window()
is never called, so it does not panic.If I
cargo build --target wasm32-wasi && wasmtime target/wasm32-wasi/debug/wasmtimeexample.wasm
, it compiles and then the expected runtime errorError: failed to run main module `target/wasm32-wasi/debug/wasmtimeexample.wasm` Caused by: 0: failed to instantiate "target/wasm32-wasi/debug/wasmtimeexample.wasm" 1: unknown import: `__wbindgen_placeholder__::__wbindgen_describe` has not been defined
gbj commented on issue #5557:
You know, I wonder if this is just that this check in
wasm-bindgen
itself is actually insufficient — it only tests whether something is a) Wasm and b) not emscripten.#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
jameysharp commented on issue #5557:
There may be ways to get wasm-bindgen to generate better code here, I don't know anything about that. But I believe the behavior you expected is available with
wasmtime --trap-unknown-imports
. Does that help?
gbj commented on issue #5557:
@jameysharp Oh fantastic, that does it! I will close this and consider opening something over in wasm-bindgen for the possible improvement there.
Thanks so much.
gbj closed issue #5557:
Feature
#3937 contains a good discussion of the problems encountered when trying to compile a program that has any
wasm-bindgen
dependencies in a WASI environment. However, this has significant effects on the ability to usewasmtime
, or any environments that usewasmtime
, to render HTML for apps created in any of the common Rust frontend frameworks. This is because virtually the whole Rust web ecosystem includingweb-sys
andjs-sys
depend onwasm-bindgen
, and they are the building blocks for all the Rust frontend web frameworks. For example, it's very common fIf you are building a native server binary, these
wasm-bindgen
ecosystem libraries compile fine, but panic if you try to run them, for obvious reasons — you are not running in the browser, so do not have access to web APIs. Frameworks are built to handle this. For example, it's very common to declare an HTML element event listener that depends on one of theweb_sys::Event
types. This can be compiled into a native server binary; it simply won't ever be run on the server, so it does not cause an issue.However, attempting to do the same in
wasmtime
causes the error in the issue linked above. See e.g., https://github.com/leptos-rs/leptos/issues/295Benefit
This would allow people to use
wasmtime
for server-side rendering in frameworks like Yew, Sycamore, Leptos, etc. that depend onweb-sys
andwasm-bindgen
, just as they can use native binaries for that same task.Implementation
I don't know enough about how
wasm-bindgen
works internally to make a real proposal, but given that none of thewasm-bindgen
code actually needs to run, it seems that the "allow it to compile and panic if called" solution used for building native binaries for other platforms should work just as well. I'm sure the fact that this seems straightforward is a testament to my own ignorance, here, so apologies.Alternatives
I've laid out a couple alternative approaches for users to this kind of issue in my reply to the issue in the Leptos repo (https://github.com/leptos-rs/leptos/issues/295)
- Leptos mocks and reexports most of
web-sys
, in a way that usesweb-sys
on the client and stubs on the server. Significant maintenance burden for the framework.- Leptos adds a wasi feature. Opting into it means you lose
web-sys
types for this and need to do something like#[cfg(not(feature = "wasi"))]
on all your event listeners and other code that needs platform types. Significant burden on library users.- Use a Wasm-based serverless platform like Cloudflare Workers that's built on V8, so does support wasm-bindgen.
- Use a platform that lets you deploy native binaries so you can build on top of an Actix or Axum server to serve your app.
Last updated: Dec 23 2024 at 12:05 UTC