this library creates a bridge to javascript in the browser at runtime using web assembly
A foreign function interface(FFI) library for invoking Javascript functions from Web Assembly for many programming languages
setTimeout
)This project has similarities to Javascript's <function>.call(<object>,a0,a1,...)
but with the limitations of Web Assembly's function call restrictions.
note js_ffi is language agnostic, I just used Rust as example because I like it
toml
[dependencies]
js_ffi = "0.6"
```rust
use js_ffi::*;
pub fn main() -> () {
register(console.log).invoke1("Hello World");
}
html
makefile
build: @RUSTFLAGS='-C link-arg=-s' cargo build --target wasm32-unknown-unknown --release @cp target/wasm32-unknown-unknown/release/helloworld.wasm . lint: @cargo fmt serve: python3 -m http.server 8080 ```
See demo here
```rust use js_ffi::*;
fn main() { let screen = registerfunction("document.querySelector").call1(&DOCUMENT, "#screen").tojsobject(); let ctx = registerfunction("document.querySelector").call1(&screen, "#screen").tojsobject();
let fill_style = register_function("function(color){
this.fillStyle = color;
}");
let fill_rect = register_function("CanvasRenderingContext2D.prototype.fillRect");
fill_style.call_1(&ctx, "red");
fill_rect.call_4(&ctx, 0.0, 0.0, 50.0, 50.0);
fill_style.call_1(&ctx, "green");
fill_rect.call_4(&ctx, 15.0, 15.0, 50.0, 50.0);
fill_style.call_1(&ctx, "blue");
fill_rect.call_4(&ctx, 30.0, 30.0, 50.0, 50.0);
} ```
```rust use js_ffi::*;
fn main() { let btn = registerfunction("document.querySelector").call1(&DOCUMENT, "#button").tojsobject(); registerfunction("Node.prototype.addEventListener").call2( &btn, "click", createcallback0(|| { registerfunction("window.alert").invoke1("I was clicked"); }), ); } ```
Using an executor
library we can easily turn callbacks into futures and run behavior asynchronously.
```rust use js_ffi::*;
pub fn main() -> () { executor::spawn(async { let consolelog = registerfunction("console.log"); consolelog.invoke1("Hello"); sleep(1000).await; consolelog.invoke1("world!"); }); }
fn sleep(millis: u32) -> impl core::future::Future { let settimeout = registerfunction("window.setTimeout"); let (future, cb) = createcallbackfuture0(); settimeout.invoke_2(cb, millis); future } ```
Wrap third party libraries. Anything function in global space should be able to be wrapped and invoked.
```rust use js_ffi::*;
fn main() { let jqueryhandle = registerfunction("$"); let jqueryonhandle = registerfunction("jQuery.prototype.on"); let alert = registerfunction("(msg)=>window.alert(msg)");
let body = jquery_handle.invoke_1("body").to_js_object();
jquery_on_handle.call_2(
&body,
"click",
create_callback_1(move |_event| {
alert.invoke_1("I was clicked!");
}),
);
} ```
```html
```
A collection of libraries exist that expose javascript functionality so you don't have to implement it yourself. Just add them to your project and go!
register_function
. Re-use this handle as often as possible.invoke_*
function based on the number of arguments you are passing (invoke_1
,invoke_7
,etc.).JSValue
, use the appropriate call_*
function based on the number of arguments you are passing (call_1
,invoke_7
,etc.) and make sure your object is the first paramter.The script js_ffi.js
has nothing Rust specific.
js_ffi.h
js_ffi
expects an entry point main()
jsffimalloc(i32) -> i32
jsfficallback(i32,f32,f32,f32,f32,f32,f32,f32,f32,f32,f32)
0
character.js
// main.js
let w = new Worker("worker.js");
w.postMessage("go");
js
// worker.js
importScripts("https://cdn.jsdelivr.net/gh/richardanaya/js_ffi/js_ffi.js")
onmessage = function() {
js_ffi.run("helloworld.wasm");
}
This project is licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in js_ffi
by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.