A standard library for the client-side Web
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.
Donate
Patrons
This software was brought to you thanks to these wonderful people:
- Ben Berman
- Stephen Sugden
Thank you!
Examples
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 );
Closures are also 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().unwrap();
button.add_event_listener( move |_: ClickEvent| {
for anchor in document().query_selector_all( "#main a" ) {
js!( @{anchor}.style = "display: none;"; );
}
});
Exposing Rust functions to JavaScript is supported too:
#[js_export]
fn hash( string: String ) -> String {
let mut hasher = Sha1::new();
hasher.update( string.as_bytes() );
hasher.digest().to_string()
}
Then you can do this from Node.js:
var hasher = require( "hasher.js" ); // Where `hasher.js` is generated from Rust code.
console.log( hasher.hash( "Hello world!" ) );
Or you can take the same .js
file and use it in a web browser:
<script src="hasher.js"></script>
<script>
Rust.hasher.then( function( hasher ) {
console.log( hasher.hash( "Hello world!" ) );
});
</script>
If you're using Parcel you can also use our experimental Parcel plugin; first do this in your existing Parcel project:
$ npm install --save parcel-plugin-cargo-web
And then simply:
import hasher from "./hasher/Cargo.toml";
console.log( hasher.hash( "Hello world!" ) );
Design goals
- 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.
Getting started
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 a vanilla web browser environment or from Nodejsexamples/hasher-parcel
- shows how to import and call exported Rust functions in a Parcel projectpinky-web
- an NES emulator; you can play with the precompiled version here
Running the examples
-
Install cargo-web:
$ cargo install -f cargo-web
-
Go into
examples/todomvc
and start the example using one of these commands:-
Compile to WebAssembly using Rust's native WebAssembly backend (requires Rust nightly!):
$ cargo web start --target=wasm32-unknown-unknown
-
Compile to asm.js using Emscripten:
$ cargo web start --target=asmjs-unknown-emscripten
-
Compile to WebAssembly using Emscripten:
$ cargo web start --target=wasm32-unknown-emscripten
-
-
Visit
http://localhost:8000
with your browser.
For the *-emscripten
targets cargo-web
is not necessary, however
the native wasm32-unknown-unknown
which doesn't need Emscripten
requires cargo-web
to work!
Changelog
-
0.4.1
- Support for newest nightly Rust on
wasm32-unknown-unknown
- Exposed
SocketBinaryType
enum - New canvas APIs:
- Numerous new methods for
CanvasRenderingContext2d
- New types:
CanvasGradient
,CanvasPattern
,CanvasStyle
,ImageData
,TextMetrics
- Numerous new methods for
- New error types:
IndexSizeError
,NotSupportedError
,TypeError
- Support for newest nightly Rust on
-
0.4
- (breaking change) Removed
Array
andObject
variants fromValue
; these are now treated asReference
s - (breaking change) The
Value
has an extra variant:Symbol
- (breaking change) Removed:
InputElement::set_kind
InputElement::files
- (breaking change) Renamed:
KeydownEvent
->KeyDownEvent
KeyupEvent
->KeyUpEvent
KeypressEvent
->KeyPressEvent
ReadyState
->FileReaderReadyState
InputElement::value
->InputElement::raw_value
InputElement::set_value
->InputElement::set_raw_value
- (breaking change)
ArrayBuffer::new
now takes anu64
argument - (breaking change)
InputElement::set_raw_value
now takes&str
instead ofInto< Value >
- (breaking change) Changed return types:
- Every method which returned
usize
now returnsu32
INode::remove_child
now returnsNode
in theOk
case- The following now return an
u64
:ArrayBuffer::len
- The following now return an
i32
instead off64
:IMouseEvent::client_x
IMouseEvent::client_y
IMouseEvent::movement_x
IMouseEvent::movement_y
IMouseEvent::screen_x
IMouseEvent::screen_y
- The following now return a
Result
:INode::insert_before
INode::replace_child
INode::clone_node
StringMap::insert
TokenList::add
TokenList::remove
Document::create_element
IEventTarget::dispatch_event
FileReader::read_as_text
FileReader::read_as_array_buffer
FileReader::read_as_text
History::replace_state
History::go
History::back
History::forward
Location::href
Location::hash
CanvasElement::to_data_url
CanvasElement::to_blob
ArrayBuffer::new
INode::base_uri
now returns aString
instead ofOption< String >
InputElement::raw_value
now returns aString
instead ofValue
- Every method which returned
- (breaking change)
INode::inner_text
was moved toIHtmlElement::inner_text
- (breaking change)
Document::query_selector
andDocument::query_selector_all
were moved toIParentNode
- (breaking change)
IElement::query_selector
andIElement::query_selector_all
were moved toIParentNode
- (breaking change)
Document::get_element_by_id
was moved toINonElementParentNode
- (breaking change) A blanket impl for converting between arbitrary reference-like objects using
TryFrom
/TryInto
has been removed - When building using a recent
cargo-web
it's not necessary to callstdweb::initialize
norstdweb::event_loop
anymore - Support for
cdylib
crates onwasm32-unknown-unknown
- New bindings:
XmlHttpRequest
WebSocket
MutationObserver
History
TextAreaElement
CanvasElement
- New event types:
MouseDownEvent
MouseUpEvent
MouseMoveEvent
PopStateEvent
ResizeEvent
ReadyStateChange
SocketCloseEvent
SocketErrorEvent
SocketOpenEvent
SocketMessageEvent
- Initial support for the Canvas APIs
- New traits:
ReferenceType
andInstanceOf
- Add
#[derive(ReferenceType)]
instdweb-derive
crate; it's now possible to define custom API bindings outside ofstdweb
- Add
#[js_export]
procedural attribute (wasm32-unknown-unknown
only) - Add
DomException
and subtypes for passing around JavaScript exceptions IElement
now inherits fromINode
- Every interface now inherits from
ReferenceType
- Add
stdweb::traits
module to act as a prelude foruse
-ing all of our interface traits - Add
console!
macro - Most types now implement
PartialEq
andEq
- (breaking change) Removed
-
0.3
- (breaking change) Deleted
ErrorEvent
methods - (breaking change) Renamed:
LoadEvent
->ResourceLoadEvent
AbortEvent
->ResourceAbortEvent
ErrorEvent
->ResourceErrorEvent
- Add
UnsafeTypedArray
for zero cost slice passing tojs!
- Add
Once
for passingFnOnce
closures tojs!
- (breaking change) Deleted
License
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.
Contributing
See CONTRIBUTING.md