This section is for general-purpose crate authors who want to support WebAssembly.
Maybe Your Crate Already Supports WebAssembly!Review the information about what kinds of things can make a general-purpose crate not portable for WebAssembly. If your crate doesn't have any of those things, it likely already supports WebAssembly!
You can always check by running cargo build
for the WebAssembly target:
cargo build --target wasm32-unknown-unknown
If that command fails, then your crate doesn't support WebAssembly right now. If it doesn't fail, then your crate might support WebAssembly. You can be 100% sure that it does (and continues to do so!) by adding tests for wasm and running those tests in CI.
Adding Support for WebAssembly Avoid Performing I/O DirectlyOn the Web, I/O is always asynchronous, and there isn't a file system. Factor I/O out of your library, let users perform the I/O and then pass the input slices to your library instead.
For example, refactor this:
# #![allow(unused_variables)] #fn main() { use std::fs; use std::path::Path; pub fn parse_thing(path: &Path) -> Result<MyThing, MyError> { let contents = fs::read(path)?; // ... } #}
Into this:
Add# #![allow(unused_variables)] #fn main() { pub fn parse_thing(contents: &[u8]) -> Result<MyThing, MyError> { // ... } #}
wasm-bindgen
as a Dependency
If you need to interact with the outside world (i.e. you can't have library consumers drive that interaction for you) then you'll need to add wasm-bindgen
(and js-sys
and web-sys
if you need them) as a dependency for when compilation is targeting WebAssembly:
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2"
js-sys = "0.3"
web-sys = "0.3"
Avoid Synchronous I/O
If you must perform I/O in your library, then it cannot be synchronous. There is only asynchronous I/O on the Web. Use the futures
crate and the wasm-bindgen-futures
crate to manage asynchronous I/O. If your library functions are generic over some future type F
, then that future can be implemented via fetch
on the Web or via non-blocking I/O provided by the operating system.
# #![allow(unused_variables)] #fn main() { pub fn do_stuff<F>(future: F) -> impl Future<Item = MyOtherThing> where F: Future<Item = MyThing>, { // ... } #}
You can also define a trait and implement it for WebAssembly and the Web and also for native targets:
Avoid Spawning Threads# #![allow(unused_variables)] #fn main() { trait ReadMyThing { type F: Future<Item = MyThing>; fn read(&self) -> Self::F; } #[cfg(target_arch = "wasm32")] struct WebReadMyThing { // ... } #[cfg(target_arch = "wasm32")] impl ReadMyThing for WebReadMyThing { // ... } #[cfg(not(target_arch = "wasm32"))] struct NativeReadMyThing { // ... } #[cfg(not(target_arch = "wasm32"))] impl ReadMyThing for NativeReadMyThing { // ... } #}
Wasm doesn't support threads yet (but experimental work is ongoing), so attempts to spawn threads in wasm will panic.
You can use #[cfg(..)]
s to enable threaded and non-threaded code paths depending on if the target is WebAssembly or not:
# #![allow(unused_variables)] #![cfg(target_arch = "wasm32")] #fn main() { fn do_work() { // Do work with only this thread... } #![cfg(not(target_arch = "wasm32"))] fn do_work() { use std::thread; // Spread work to helper threads.... thread::spawn(|| { // ... }); } #}
Another option is to factor out thread spawning from your library and allow users to "bring their own threads" similar to factoring out file I/O and allowing users to bring their own I/O. This has the side effect of playing nice with applications that want to own their own custom thread pool.
Maintaining Ongoing Support for WebAssembly Building forwasm32-unknown-unknown
in CI
Ensure that compilation doesn't fail when targeting WebAssembly by having your CI script run these commands:
rustup target add wasm32-unknown-unknown
cargo check --target wasm32-unknown-unknown
For example, you can add this to your .travis.yml
configuration for Travis CI:
matrix:
include:
- language: rust
rust: stable
name: "check wasm32 support"
install: rustup target add wasm32-unknown-unknown
script: cargo check --target wasm32-unknown-unknown
Testing in Node.js and Headless Browsers
You can use wasm-bindgen-test
and the wasm-pack test
subcommand to run wasm tests in either Node.js or a headless browser. You can even integrate these tests into your CI.
Learn more about testing wasm here.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4