New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[napi] Support WebAssembly #796
Comments
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. |
You misunderstood, this issue actually expects to provide an ability to bind wasm-bindgen. |
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? |
It's not possible for #[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
} |
Unless i've missed something, I still don't quite understand the use case for this. |
Image you have a library like use crc32;
#[napi]
fn crc32(input: Buffer) -> u32 {
crc32::caclulate(input.as_slice())
} With the WebAssembly support, you can just run The code will be totally reused. |
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. |
Yes, this will be released in |
I'm curious what the plan is for how Tasks will be supported in Wasm. I use Anyways some food for thought as this issue is explored. |
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? |
When is version 3.0 planned to be released? |
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 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. |
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. |
Successfully make emnapi work with napi-rs and wasi-sdk I compiled the rust code into a static library of the |
Very cool! I'm curious what the advantage of using Emscripten for this is vs implementing it in JS? I see you have part implemented in C and a separate bridge layer in JS, which is very similar to how wasm-bindgen works. But why is that extra layer needed? Seems more straightforward to just implement napi in JS and inject it as an external library into the WASM module as I've done in https://github.com/devongovett/napi-wasm. Adding Emscripten and a whole extra layer seems like it would complicate the build and increase the binary size potentially. |
Only the following things implemented in C:
To make the behavior close to Node.js as much as possible, emnapi has ported libuv's threadpool which is required by async work related API, and this uses emscripten's pthread support, and the C implementation is rewrite according to Node.js source code. Other API implemented in JavaScript is also consistent with the behavior of the nodejs source code, I have separated JS runtime code to npm package to make the runtime reusable for non-emscripten environment.
No, we do not need emscripten. But maybe we need wasi-sdk in the future due to emnapi C implementation use the C library and pthread. toyobayashi/emnapi#29 is working on non-emscripten support. |
Currently the latest version wasi-sdk 19 has no threads support yet, so pthread related APIs are unavailable. napi-rs cli could find emnapi precompiled static library to link, I plan to publish static library precompiled by clang in next version Two approach:
|
The real world use case of emnapi, though not many, it is functionally reliable. |
Ah I see. I think it would be nice to avoid relying on Emscripten for pthreads etc. Same with WASI – I don't think WASI is available in browsers (yet?). I was going to look into how wasm-bindgen-rayon implemented WASM threads (I think they are just web workers) and follow that for napi-wasm, but I haven't had time yet. |
emnapi is design for emscripten at first, for convenience I use pthread to port libuv threadpool and async work / tsfn implementation of Node.js to pure C. It's a bit hard for me if replace the pthread part then still keep passing all nodejs official test.
I did this in https://github.com/toyobayashi/wasm-util/tree/main/src/wasi, by rewriting uvwasi in JavaScript, optionally use |
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 |
Is there a plan for getting rid of |
@devongovett I'm working on it on this branch: https://github.com/napi-rs/napi-rs/tree/emnapi |
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 for (let key in instance.exports) {
if (key.startsWith('__napi_register__')) {
instance.exports[key]();
}
} As long as that is done before calling |
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 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. |
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. |
@devongovett I can split changes in abbea85 and merge it before WebAssembly implemented, so that you can call the register functions before |
Thanks @Brooooooklyn, that would be helpful! I'm also happy to use the ctor patch in the meantime if it's too hard. |
@devongovett published |
I think basic webassembly support is nearly there: |
Closed in #1669 |
By integrating with wasm_bindgen, we can get WASM support.
Once supported, we can automate what this PR does: parcel-bundler/lightningcss#1
The text was updated successfully, but these errors were encountered: