How to Add WebAssembly Support to a General-Purpose Crate

    Review the information about what kinds of things can make a general-purposecrate not portable for WebAssembly. Ifyour crate doesn't have any of those things, it likely already supportsWebAssembly!

    You can always check by running for the WebAssembly target:

    If that command fails, then your crate doesn't support WebAssembly right now. Ifit doesn't fail, then your crate might support WebAssembly. You can be 100%sure that it does (and continues to do so!) by

    On the Web, I/O is always asynchronous, and there isn't a file system. FactorI/O out of your library, let users perform the I/O and then pass the inputslices to your library instead.

    1. # #![allow(unused_variables)]
    2. #fn main() {
    3. use std::fs;
    4. use std::path::Path;
    5. pub fn parse_thing(path: &Path) -> Result<MyThing, MyError> {
    6. let contents = fs::read(path)?;
    7. // ...
    8. }
    9. #}

    Into this:

    1. # #![allow(unused_variables)]
    2. #fn main() {
    3. pub fn parse_thing(contents: &[u8]) -> Result<MyThing, MyError> {
    4. }
    5. #}

    Add wasm-bindgen as a Dependency

    If you need to interact with the outside world (i.e. you can't have libraryconsumers 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 whencompilation is targeting WebAssembly:

    If you must perform I/O in your library, then it cannot be synchronous. There isonly asynchronous I/O on the Web. Use and the wasm-bindgen-futurescrate tomanage asynchronous I/O. If your library functions are generic over somefuture type F, then that future can be implemented via fetch on the Web orvia non-blocking I/O provided by the operating system.

    1. # #![allow(unused_variables)]
    2. #fn main() {
    3. pub fn do_stuff<F>(future: F) -> impl Future<Item = MyOtherThing>
    4. where
    5. F: Future<Item = MyThing>,
    6. {
    7. // ...
    8. }
    9. #}

    You can also define a trait and implement it for WebAssembly and the Web andalso for native targets:

    1. # #![allow(unused_variables)]
    2. #fn main() {
    3. trait ReadMyThing {
    4. type F: Future<Item = MyThing>;
    5. fn read(&self) -> Self::F;
    6. }
    7. #[cfg(target_arch = "wasm32")]
    8. struct WebReadMyThing {
    9. // ...
    10. }
    11. #[cfg(target_arch = "wasm32")]
    12. impl ReadMyThing for WebReadMyThing {
    13. // ...
    14. #[cfg(not(target_arch = "wasm32"))]
    15. struct NativeReadMyThing {
    16. // ...
    17. }
    18. #[cfg(not(target_arch = "wasm32"))]
    19. impl ReadMyThing for NativeReadMyThing {
    20. // ...
    21. }
    22. #}

    Avoid Spawning Threads

    You can use #[cfg(..)]s to enable threaded and non-threaded code pathsdepending on if the target is WebAssembly or not:

    Another option is to factor out thread spawning from your library and allowusers to "bring their own threads" similar to factoring out file I/O andallowing users to bring their own I/O. This has the side effect of playing nicewith applications that want to own their own custom thread pool.

    Ensure that compilation doesn't fail when targeting WebAssembly by having yourCI script run these commands:

    1. rustup target add wasm32-unknown-unknown
    2. cargo check --target wasm32-unknown-unknown

    For example, you can add this to your .travis.yml configuration for Travis CI:

    1. matrix:
    2. include:
    3. - language: rust
    4. rust: stable
    5. name: "check wasm32 support"
    6. install: rustup target add wasm32-unknown-unknown

    Testing in Node.js and Headless Browsers