The goal of this crate is to provide Rust bindings to the Web APIs and to allow a high degree of interoperability between Rust and JavaScript.
You can directly embed JavaScript code into Rust:
let message = "Hello, 世界!";
let result = js! {
alert( @{message} );
return 2 + 2 * 2;
};
println!( "2 + 2 * 2 = {:?}", result );
Even closures are supported:
let print_hello = |name: String| {
println!( "Hello, {}!", name );
};
js! {
var print_hello = @{print_hello};
print_hello( "Bob" );
print_hello.drop(); // Necessary to clean up the closure on Rust's side.
}
You can also pass arbitrary structures thanks to serde:
#[derive(Serialize)]
struct Person {
name: String,
age: i32
}
js_serializable!( Person );
js! {
var person = @{person};
console.log( person.name + " is " + person.age + " years old." );
};
This crate also exposes a number of Web APIs, for example:
let button = document().query_selector( "#hide-button" ).unwrap();
button.add_event_listener( move |_: ClickEvent| {
for anchor in document().query_selector_all( "#main a" ) {
js!( @{anchor}.style = "display: none;"; );
}
});
- Expose a full suite of Web APIs as exposed by web browsers.
- Try to follow the original JavaScript conventions and structure as much as possible, except in cases where doing otherwise results in a clearly superior design.
- Be a building block from which higher level frameworks and libraries can be built.
- Make it convenient and easy to embed JavaScript code directly into Rust and to marshal data between the two.
- Integrate with the wider Rust ecosystem, e.g. support marshaling of structs which implement serde's Serializable.
- Put Rust in the driver's seat where a non-trivial Web application can be written without touching JavaScript at all.
- Allow Rust to take part in the upcoming WebAssembly (re)volution.
- Make it possible to trivially create standalone libraries which are easily callable from JavaScript.
Take a look at some of the examples:
examples/minimal
- a totally minimal example which calls alertexamples/todomvc
- a naively implemented TodoMVC application; shows how to call into the DOMexamples/hasher
- shows how to export Rust functions to JavaScript and how to call them from the browser or Nodejs
-
Add one of Rust's Web targets with rustup.
-
For compiling to asmjs through Emscripten:
$ rustup target add asmjs-unknown-emscripten
-
For compiling to WebAssembly through Emscripten:
$ rustup target add wasm32-unknown-emscripten
-
For compiling to WebAssembly through Rust's native backend:
$ rustup target add wasm32-unknown-unknown
-
-
Install cargo-web:
$ cargo install -f cargo-web
-
Go into
examples/todomvc
and start the example.-
For the
asmjs-unknown-emscripten
backend:$ cargo web start --target-asmjm-emscripten
-
For the
wasm32-unknown-emscripten
:$ cargo web start --target-webasm-emscripten
-
For the
wasm32-unknown-unknown
:$ cargo web start --target-webasm
-
-
Visit
http://localhost:8000
with your browser.
For the *-emscripten
targets cargo-web
is not neccessary, however
the native wasm32-unknown-unknown
which doesn't need Emscripten
requires cargo-web
to work!
WARNING: This is only supported for Rust's native wasm32-unknown-unknown
target!
(Note: this is based on the examples/hasher
example)
With the stdweb
crate you can easily expose a Rust function
to JavaScript like this:
#[macro_use]
extern crate stdweb;
extern crate sha1;
use sha1::Sha1;
fn hash( string: String ) -> String {
let mut hasher = Sha1::new();
hasher.update( string.as_bytes() );
hasher.digest().to_string()
}
fn main() {
stdweb::initialize();
js! {
Module.exports.sha1 = @{hash};
}
}
If you compile this code with cargo-web build --target-webasm
you'll get two files:
target/wasm32-unknown-unknown/release/hasher.js
target/wasm32-unknown-unknown/release/hasher.wasm
You can copy them into your JavaScript project and load like any other JavaScript file:
<script src="hasher.js"></script>
After it's loaded you can access Rust.hasher
, which is a Promise which
will resolve once the WebAssembly module is loaded. Inside that promise
you'll find the contents of Module.exports
which we've set from our
Rust code, which includes our exported function which you can now call:
<script>
Rust.hasher.then( function( hasher ) {
const string = "fiddlesticks";
const hash = hasher.sha1( string );
console.log( "Hash of " + string + " is '" + hash + "'" );
});
</script>
You can also use the very same hasher.js
from Nodejs:
const hasher = require( "hasher.js" );
const string = "fiddlesticks";
const hash = hasher.sha1( string );
console.log( "Hash of " + string + " is '" + hash + "'" );
For the Nodejs environment the WebAssembly is compiled synchronously.
Licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Snippets of documentation which come from Mozilla Developer Network are covered under the CC-BY-SA, version 2.5 or later.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.