Stream: git-wasmtime

Topic: wasmtime / issue #5557 Wasmtime: Allow importing types th...


view this post on Zulip Wasmtime GitHub notifications bot (Jan 11 2023 at 14:17):

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 use wasmtime, or any environments that use wasmtime, to render HTML for apps created in any of the common Rust frontend frameworks. This is because virtually the whole Rust web ecosystem including web-sys and js-sys depend on wasm-bindgen, and they are the building blocks for all the Rust frontend web frameworks. For example, it's very common f

If 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 the web_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/295

Benefit

This would allow people to use wasmtime for server-side rendering in frameworks like Yew, Sycamore, Leptos, etc. that depend on web-sys and wasm-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 the wasm-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)

  1. Leptos mocks and reexports most of web-sys, in a way that uses web-sys on the client and stubs on the server. Significant maintenance burden for the framework.
  2. 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.
  3. Use a Wasm-based serverless platform like Cloudflare Workers that's built on V8, so does support wasm-bindgen.
  4. 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.

view this post on Zulip Wasmtime GitHub notifications bot (Jan 11 2023 at 15:01):

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 of wasm-bindgen, however, I don't think that this would be a good idea.

"Support wasm-bindgen outside of a browser" would basically involve:

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.

view this post on Zulip Wasmtime GitHub notifications bot (Jan 11 2023 at 15:49):

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.

view this post on Zulip Wasmtime GitHub notifications bot (Jan 11 2023 at 16:05):

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, printing Hello, world!.

If I cargo build --target wasm32-wasi && wasmtime target/wasm32-wasi/debug/wasmtimeexample.wasm, it compiles and then the expected runtime error

Error: 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

view this post on Zulip Wasmtime GitHub notifications bot (Jan 11 2023 at 16:05):

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, printing Hello, 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 error

Error: 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

view this post on Zulip Wasmtime GitHub notifications bot (Jan 11 2023 at 16:12):

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"))))]

view this post on Zulip Wasmtime GitHub notifications bot (Jan 11 2023 at 16:45):

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?

view this post on Zulip Wasmtime GitHub notifications bot (Jan 11 2023 at 17:05):

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.

view this post on Zulip Wasmtime GitHub notifications bot (Jan 11 2023 at 17:05):

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 use wasmtime, or any environments that use wasmtime, to render HTML for apps created in any of the common Rust frontend frameworks. This is because virtually the whole Rust web ecosystem including web-sys and js-sys depend on wasm-bindgen, and they are the building blocks for all the Rust frontend web frameworks. For example, it's very common f

If 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 the web_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/295

Benefit

This would allow people to use wasmtime for server-side rendering in frameworks like Yew, Sycamore, Leptos, etc. that depend on web-sys and wasm-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 the wasm-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)

  1. Leptos mocks and reexports most of web-sys, in a way that uses web-sys on the client and stubs on the server. Significant maintenance burden for the framework.
  2. 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.
  3. Use a Wasm-based serverless platform like Cloudflare Workers that's built on V8, so does support wasm-bindgen.
  4. 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