Sitelet https://github.com/napi-rs/napi-rs/issues/796#issuecomment-1416013206
Skip to content

[napi] Support WebAssembly #796

Description

@yisibl

By integrating with wasm_bindgen, we can get WASM support.

Once supported, we can automate what this PR does: parcel-bundler/lightningcss#1

Activity

  1. BasixKOR commented on Oct 25, 2021

    @BasixKOR

    It won't make sense anyway. N-API is Node-js-only feature that doesn't work on the web and wasm-bindgen is already doing a good job in this field.

  2. yisibl commented on Oct 25, 2021

    @yisibl
    CollaboratorAuthor

    You misunderstood, this issue actually expects to provide an ability to bind wasm-bindgen.

  3. daniel-brenot commented on Oct 31, 2021

    @daniel-brenot

    Why though? If you wish to call wasm rust from js you can do that with wasm-bindgen. This library exists to allow running specifically native code. Could you elaborate your intent if we have misunderstood?

  4. Brooooooklyn commented on Oct 31, 2021

    @Brooooooklyn
    SponsorMember

    It's not possible for napi-rs 1.x to support wasm, but with the procedural macro introduced in 2.0, we can generate code for Rust WASM compiling. For example:

    #[napi]
    fn add(a: u32, b: u32) -> u32 {
      a + b
    }

    We can generate wasm bindgen code for the wasm compile target:

    #[wasm_bindgen]
    fn add(a: u32, b: u32) -> u32 {
      a + b
    }
  5. daniel-brenot commented on Oct 31, 2021

    @daniel-brenot

    Unless i've missed something, I still don't quite understand the use case for this.

  6. Brooooooklyn commented on Oct 31, 2021

    @Brooooooklyn
    SponsorMember

    Image you have a library like crc32:

    use crc32;
    
    #[napi]
    fn crc32(input: Buffer) -> u32 {
      crc32::caclulate(input.as_slice())
    }

    With the WebAssembly support, you can just run napi build --release to build native addons. And run napi build --release --target wasm32-unknown-unknown to build wasm library.

    The code will be totally reused.

  7. daniel-brenot commented on Oct 31, 2021

    @daniel-brenot

    So then the use case is to reuse the same code to produce a native bindgen or a wasm bindgen? If so, that sounds like a great feature.

  8. Brooooooklyn commented on Oct 31, 2021

    @Brooooooklyn
    SponsorMember

    So then the use case is to reuse the same code to produce a native bindgen or a wasm bindgen

    Yes, this will be released in 3.0

  9. nickbabcock commented on Dec 19, 2021

    @nickbabcock

    I'm curious what the plan is for how Tasks will be supported in Wasm. I use napi-rs to run compute heavy tasks off the main thread and I'm not sure how well that translates to the browser. Would it be on the user's responsibility to ensure that the napi-rs produced Wasm is executed in a web worker (so tasks would only are computed off the execution thread in node.js) or would napi-rs produce an output that would manage a pool of web workers to run shuffle tasks around.

    Anyways some food for thought as this issue is explored.

  10. janus-reith commented on Jan 5, 2022

    @janus-reith

    I use napi-rs to run compute heavy tasks off the main thread and I'm not sure how well that translates to the browser.

    While the output should be able to run in a browser too, I believe the main target here would be server-side executed wasm, in general I assume implementation details like if the output should run in a worker would be up to the user?

  11. Kayshen-X commented on Feb 17, 2022

    @Kayshen-X

    So then the use case is to reuse the same code to produce a native bindgen or a wasm bindgen

    Yes, this will be released in 3.0

    When is version 3.0 planned to be released?

  12. devongovett commented on Dec 29, 2022

    @devongovett
    Contributor

    I kinda got this working a different way - by reimplementing napi in JS so it can be used from WASM: https://github.com/devongovett/napi-wasm. I'm planning on using it in lightningcss to avoid having two separate implementations, which is getting to be more work as we add more features. With this, the existing napi implementation just works when recompiled for WASM.

    I ran the napi-rs compat mode test suite using it and it mostly passes, minus some features that don't work in WASM (like threads and fs access). In addition, there are a few other features that don't work because napi-rs uses the #[ctor] attribute which is currently not supported in wasm targets (see wasm-bindgen/wasm-bindgen#1216). To work around that, I manually implemented napi_register_wasm_v1 and registered my exports in there (see example in the readme). But that won't work for other features in the napi bindgen API which use ctors to register things for later use in napi_register_module_v1. Perhaps there is some other way of doing that though.

    Anyway, maybe this approach is easier than modifying all of napi-rs to have two completely different implementations? Most of what's being done in napi-wasm is similar to what wasm-bindgen generates anyway.

  13. toyobayashi commented on Jan 24, 2023

    @toyobayashi
    Contributor

    I created https://github.com/toyobayashi/emnapi for emscripten, well tested by using Node.js official test cases, and it support async work and thread-safe functions on modern browsers (based on emscripten pthreads). I'm not familiar with rust, not sure if it can help.

  14. 8 remaining items

  15. toyobayashi commented on Feb 4, 2023

    @toyobayashi
    Contributor

    Additionally i would like to explain, emnapi's goal is 1) help users port their or existing node-api native addons to wasm with code change as less as possible, 2) runtime behavior matches native Node.js as much as possible.

    So I decided to port Node.js node-api source code implementation to JavaScript and C, if you have look into emnapi's source code, you could see most code (both TS and C) matches Nodejs's src/js_native_api_v8.cc and src/node_api.cc. Relying on pthread is reasonable and it is the best way to achieve 2) because I can port part of libuv, do tsfn mutex lock/unlock and cond wait/signal exactly same as nodejs. As most addons are written in C/C++, emscripten is still the first class support target, then wasi-sdk, napi-rs could also be supported if @Brooooooklyn approve emnapi's practice. WASI is the standard, I could not find some reason to avoid it.

  16. moved this to In Progress in napi 3.0on Mar 1, 2023
  17. devongovett commented on Mar 15, 2023

    @devongovett
    Contributor

    Is there a plan for getting rid of #[ctor] in napi? At the moment this blocks us from using the modern napi-rs API in Parcel. We instead have to fall back to the old API if we want to support WASM. Maybe there is a way we could disable ctor for wasm targets and somehow manually call the initialization functions?

  18. Brooooooklyn commented on Mar 16, 2023

    @Brooooooklyn
    SponsorMember
  19. devongovett commented on Mar 16, 2023

    @devongovett
    Contributor

    Cool, thanks. Hopefully it won't require WASI though? Not sure that will work in browsers.

    In the meantime, I got it working by patching rust-ctor: devongovett/rust-ctor@30aa204. All that does is mark the ctor functions as #[no_mangle] in wasm32 targets. Then, I just have to do this from the JS:

    for (let key in instance.exports) {
      if (key.startsWith('__napi_register__')) {
        instance.exports[key]();
      }
    }

    As long as that is done before calling napi_register_module_v1 it seems to work. 🥳

  20. toyobayashi commented on Mar 16, 2023

    @toyobayashi
    Contributor

    Hopefully it won't require WASI though?

    Working in progress, no WASI required for async work and tsfn! Currently emnapi already has another TSFN implementation and single thread async work mock, both are implemented in pure JavaScript and passed node js official test suite. I'll bring real multithreaded async work implementation via WebWorkers in next release. emnapi users can decide themselves to use
    async work / tsfn 's C or JS implementation.

    According to @Brooooooklyn , napi-rs uses tokio, unfortunately they still need WASI, but emnapi itself can avoid WASI soon. My WASI polyfill is well tested in browser as well.

  21. devongovett commented on Mar 16, 2023

    @devongovett
    Contributor

    For my use cases, I don't really need support for tokio or async work in WASM so I wouldn't really mind if there were some features of napi-rs that were only for non-WASM targets. It would be great if we could ensure that those features are optional and that large polyfills aren't required unless you explicitly include them. I mainly need the basics to work: calling Rust from JS, and JS from Rust. Once in Rust-land, I'm happy to manage things like async tasks myself.

  22. Brooooooklyn commented on Mar 16, 2023

    @Brooooooklyn
    SponsorMember

    @devongovett I can split changes in abbea85 and merge it before WebAssembly implemented, so that you can call the register functions before napi_register_module_v1 with these changes.

  23. devongovett commented on Mar 16, 2023

    @devongovett
    Contributor

    Thanks @Brooooooklyn, that would be helpful! I'm also happy to use the ctor patch in the meantime if it's too hard.

  24. Brooooooklyn commented on Mar 21, 2023

    @Brooooooklyn
    SponsorMember

    @devongovett published napi-derive@2.12.1 for that, you can try it!

  25. AlexMikhalev commented on Jul 19, 2023

    @AlexMikhalev

    I think basic webassembly support is nearly there:
    I compiled code with #[napi] derive into wasm using cargo build --release --target=wasm32-unknown-unknown but yarn build fails:
    yarn run build --target=wasm32-unknown-unknown Finished release [optimized] target(s) in 0.02s Type Error: Operating system not currently supported or recognized by the build script
    with @napi-rs/cli/scripts/index.js:11540:31.
    I am ok not having threads and tokio and others since even Wasi runtime doesn't support any of it.
    But being able to hook into a browser or native is a killer feature.

  26. Brooooooklyn commented on Nov 7, 2023

    @Brooooooklyn
    SponsorMember

    Closed in #1669

  27. moved this from In Progress to Done in napi 3.0on Nov 7, 2023
  28. unpinned this issue on Nov 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    • Status
      Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions