bytecodealliance / wasm-tools

CLI and Rust libraries for low-level manipulation of WebAssembly modules
Apache License 2.0
1.34k stars 245 forks source link

Online playground #1595

Closed bakkot closed 5 months ago

bakkot commented 5 months ago

I have occasionally wanted to use these tools on the web. I've used wat2wasm and the other playgrounds from wabt a lot, and the lack of a similar easy way of using wasm-tools keeps tripping me up.

Would you accept a PR which adds a GitHub action which uses the wasm32-wasi artifact from a release and wraps it up with a browser-based wasi implementation to live on GitHub Pages? I'm imagining something very simple, just a text box / file upload for input and a text box / download button for output plus a place to enter the command and see stdout/stderr.

alexcrichton commented 5 months ago

Thanks for the report, and I'd love to see this! I've never been certain enough of what I'd want this to look like to implement it but I think it'd be great to have!

For some of the technical bits it should be ok to actually skip wasi support and use the wasm32-unknown-unknown target since most of the libraries don't need the filesystem or env vars or things like that. If you're ok with it I think it would be best to architect this as something which lives in-tree and is deployed to github pages on all merges to main. I'm happy to help with the CI bits here too.

As for the actual integration with the web, I might recommend one of two approaches:

Whichever you find easiest I think would be a great place to start. If you need any help please just let me know!

bakkot commented 5 months ago

Dogfooding sounds fun, but I'd probably need more help with it. I expect I could whip something up with wasm-bindgen largely on my own.

For the dogfooding option, what would the process actually look like, concretely? It looks like wit-component isn't meant to be used directly, in preference for cargo component, so would the idea be to do cargo install cargo-component in CI, and then cargo component build --target wasm32-unknown-unknown followed by jco transpile?

alexcrichton commented 5 months ago

Starting with wasm-bindgen sounds reasonable to me. My thinking is that a jco based experience would be as you mention, but that's mostly just to lean into components I don't think it is substantially different than wasm-bindgen at this time otherwise.

bakkot commented 5 months ago

The cargo-component approach was actually fairly straightforward,

Unfortunately the wasm32-unknown-unknown target immediately panics (i.e., hits an unreachable wasm instruction) if I try to wat::parse_str anything nontrivial.

Building for wasm32-wasi works, and from checking the output, it seems to be pulling in environ_get, environ_sizes_get, fd_write, proc_exit, and random_get. Of those, it only actually calls random_get, which I'm guessing is where the pani comes from.

I see that wasmparser has a feature to disable hash maps, but I don't know why wasmparser would be involved here. In any case, adding wasmparser = { path = "../../crates/wasmparser", features = ["no-hash-maps"] } did not change anything. Maybe there's a different thing I need to do to disable it?

alexcrichton commented 5 months ago

It's true yeah with wasm32-unknown-unknown debugging isn't fun, and you'd probably need something like console_error_panic_hook to help debug the unreachable (which is probably a rust panic).

Stubbing a small set of wasm32-wasi functions like that shouldn't be too hard though, things like environ_* could be noops returning zero-size things.

In theory you shouldn't need to frob hash maps at all, randomness is used by default on wasi but it won't panic on wasm32-unknown-unknown.