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.
This software was brought to you thanks to these wonderful people:
- Embark Studios
- Joe Narvaez
- Eduard Knyshov
- Anselm Eickhoff
- Johan Andersson
- Stephen Sugden
- is8ac
Thank you!
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!" ) );- 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 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
The API documentation is also available for you to look at.
-
Install cargo-web:
$ cargo install -f cargo-web -
Go into
examples/todomvcand start the example using one of these commands:-
Compile to WebAssembly using Rust's native WebAssembly backend:
$ 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:8000with 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!
-
stdweb 0.4.20- Compatibility with the newest
wasm-bindgen - New events:
FullscreenChangeEvent
- Compatibility with the newest
-
stdweb 0.4.19- New methods:
Document::fullscreen_enabledDocument::fullscreen_elementInputElement::selection_startInputElement::selection_endInputElement::set_selection_startInputElement::set_selection_endObject::to_iterWindow::confirm
&Arrays can now be converted toVecs throughTryFrom- The runtime should now be compatible with newer versions of Emscripten
- The unstable
futures-related APIs were updated to work with the latest nightlies - The
syndependency was updated to version 1
- New methods:
-
stdweb 0.4.18- The
js!macro can now be imported with anuse - New events:
BeforeUnloadEventUnloadEvent
- New methods:
IBlob::sliceIBlob::slice_with_content_typeIWindowOrWorker::set_clearable_timeout
- The
-
stdweb 0.4.17- The unstable
futures-related APIs were updated to work with the latest nightlies
- The unstable
-
stdweb 0.4.16- Initial
wasm-bindgencompatibility; you can now usestdwebin projects usingwasm-bindgen - Minimum supported Rust version is now 1.33.0
- Minimum required
cargo-webversion is now 0.6.24
- Initial
-
stdweb 0.4.15- The unstable
futures-related APIs were updated to work with the latest nightlies - New types:
FormDataFormDataEntryMouseButtonsState
- New methods:
Blob::new
- The unstable
-
stdweb 0.4.14- The
js!macro now generates slightly more efficient code if you're not returning anything from your JS snippet. This makes it unnecessary to add the@(no_return)annotation in the vast majority of cases. - New types:
File
- The
-
stdweb 0.4.13- Fixed the procedural
js!macro's whitespace handling - New types:
ITouchEventTouchTouchType
- New events:
TouchEventTouchMoveTouchLeaveTouchEnterTouchEndTouchCancelTouchStart
- New methods:
XmlHttpRequest::set_response_type
- Fixed the procedural
-
stdweb 0.4.12- Improved diagnostics when trying to compile for the
wasm32-unknown-unknowntarget withoutcargo-web
- Improved diagnostics when trying to compile for the
-
stdweb 0.4.11- The minimum required Rust version is now 1.30.1
- The minimum required
cargo-webversion is now 0.6.22 wasm32-unknown-unknownis now officially supported on stable Rust- Debug builds on
wasm32-unknown-unknownare now supported - The
js!macro is now partially implemented using a procedural macro - String decoding/encoding is now a lot faster due to the use of native codec APIs
- New methods:
Document::import_nodeIElement::slotIElement::attach_shadowIElement::shadow_root
- New types:
ISlotableShadowRootShadowRootModeTemplateElementSlotElement
- New events:
SlotChangeEvent
IParentNode::query_selectorandIParentNode::query_selector_allnow return a proper error type
-
stdweb 0.4.10,stdweb-derive 0.5.1- New methods:
IElement::insert_adjacent_htmlIElement::insert_html_beforeIElement::insert_html_afterIElement::prepend_htmlIElement::append_htmlIElement::namespace_uriIElement::closestDocument::create_element_nsWindow::get_selection
- New types:
AbortErrorSelectionTypeSelectionRange
- The error messages for failed type conversions are now improved
- The error type of failed conversions (when using
.try_into()/.try_from()) is now convertible into aTypeError - Aggregate error types (like, e.g.
DrawImageError) are now serializable through thejs!macro TypeErroris now fixed (it was incorrectly treated as aDOMException)Numbercan now be converted intof64with.into()/.from()- Added
Mut, which is a new wrapper type for safely passingFnMutclosures into thejs!macro; it is optional for now, however the usage of this wrapper type will be mandatory in the future! FnMutclosures cannot be called recursively anymore#[derive(ReferenceType)]now supports a limited subset of generic types- Asynchronous unit tests are now supported with a new
#[async_test]attribute macro (nightly only) - Updated to
futures 0.3(nightly only)
- New methods:
-
stdweb 0.4.9,stdweb-derive 0.5.0- Performance improvements; serialization through serde is now twice as fast
- New events:
ScrollEventDragRelatedEventDragEventDragStartEventDragEndEventDragEnterEventDragLeaveEventDragOverEventDragExitEventDragDropEvent
- New types:
DataTransferEffectAllowedDropEffectDataTransferItemListDataTransferItemDataTransferItemKindIDragEvent
Values can now be converted toOption< Serde< T > >withtry_into- Deserialization of numbers through serde now works in the majority of cases
allowing types other than
i32andf64to be used - All of the events are now more strongly-typed
- Previously in was possible to deserialize e.g. a
keyupevent as aKeyDownEventsince only the event's JS type was checked and bothkeyupandkeydownshare the same JS type (KeyboardEvent). From now on thetypefield of the event is also checked, so such conversions are not allowed anymore.
- Previously in was possible to deserialize e.g. a
-
0.4.8- Fixed compilation on the newest nightly when targeting
wasm32-unknown-unknown - New events:
PointerLockChangeEventPointerLockErrorEventMouseWheelEvent
- New types:
MouseWheelDeltaModeXhrResponseType
- New methods:
XmlHttpRequest::raw_responseWindow::device_pixel_ratioDocument::pointer_lock_elementDocument::exit_pointer_lock
- Fixed compilation on the newest nightly when targeting
-
0.4.7- New events:
AuxClickEventMouseEnterEventMouseLeaveEventContextMenuEventSelectionChangeEvent
- New types:
FileListFileReaderReadyState
- Implement gamepad APIs:
GamepadGamepadButtonGamepadButtonMappingGamepadEvent
- Fixed
CanvasRenderingContext2d::clear_rect - Fixed a leak when creating
TypedArrays fromVecs andArrayBuffers.
- New events:
-
0.4.6- Fix
docs.rsagain - New types:
SubmitEventIChildNode
- Fix
CanvasElement::to_data_url
- Fix
-
0.4.5- New types:
DocumentFragmentSelectElementOptionElementHtmlCollection
- New methods:
Node::from_htmlValue::is_null
- Expose enums:
SocketMessageDataNodeType
- Update to
futures0.2
- New types:
-
0.4.4- Fix
docs.rs(hopefully). - New methods:
Location::originLocation::protocolLocation::hostLocation::hostnameLocation::portLocation::pathnameLocation::search
- These now return
SecurityErrorin the error case:Location::hashLocation::href
- Fix
-
0.4.3- Objects which cannot be used as keys in a
WeakMapshould be supported now (e.g. some of the WebGL-related objects under Firefox) - New methods:
Element::get_bounding_client_rectElement::scroll_topElement::scroll_leftWindow::page_x_offsetWindow::page_y_offsetNodeList::itemDocument::bodyDocument::headDocument::titleDocument::set_titleIMouseEvent::offset_xIMouseEvent::offset_y
- Expose more canvas related types:
CompositeOperationLineCapLineJoinRepetitionTextAlignTextBaseline
- Expose canvas related error types:
AddColorStopError,DrawImageError,GetImageDataError - New events:
MouseOverEventMouseOutEventPointerOverEventPointerEnterEventPointerDownEventPointerMoveEventPointerUpEventPointerCancelEventPointerOutEventPointerLeaveEventGotPointerCaptureEventLostPointerCaptureEvent
- New interface for pointer events:
IPointerEvent
- Objects which cannot be used as keys in a
-
0.4.2- Fixed a leak when deserializing references
- Fixed
CanvasRenderingContext2d::get_canvas - Exposed
FillRuleandSocketReadyState - New attribute related methods added to
IElement - New
Datebindings
-
0.4.1- Support for newest nightly Rust on
wasm32-unknown-unknown - Exposed
SocketBinaryTypeenum - 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
ArrayandObjectvariants fromValue; these are now treated asReferences - (breaking change) The
Valuehas an extra variant:Symbol - (breaking change) Removed:
InputElement::set_kindInputElement::files
- (breaking change) Renamed:
KeydownEvent->KeyDownEventKeyupEvent->KeyUpEventKeypressEvent->KeyPressEventReadyState->FileReaderReadyStateInputElement::value->InputElement::raw_valueInputElement::set_value->InputElement::set_raw_value
- (breaking change)
ArrayBuffer::newnow takes anu64argument - (breaking change)
InputElement::set_raw_valuenow takes&strinstead ofInto< Value > - (breaking change) Changed return types:
- Every method which returned
usizenow returnsu32 INode::remove_childnow returnsNodein theOkcase- The following now return an
u64:ArrayBuffer::len
- The following now return an
i32instead off64:IMouseEvent::client_xIMouseEvent::client_yIMouseEvent::movement_xIMouseEvent::movement_yIMouseEvent::screen_xIMouseEvent::screen_y
- The following now return a
Result:INode::insert_beforeINode::replace_childINode::clone_nodeStringMap::insertTokenList::addTokenList::removeDocument::create_elementIEventTarget::dispatch_eventFileReader::read_as_textFileReader::read_as_array_bufferFileReader::read_as_textHistory::replace_stateHistory::goHistory::backHistory::forwardLocation::hrefLocation::hashCanvasElement::to_data_urlCanvasElement::to_blobArrayBuffer::new
INode::base_urinow returns aStringinstead ofOption< String >InputElement::raw_valuenow returns aStringinstead ofValue
- Every method which returned
- (breaking change)
INode::inner_textwas moved toIHtmlElement::inner_text - (breaking change)
Document::query_selectorandDocument::query_selector_allwere moved toIParentNode - (breaking change)
IElement::query_selectorandIElement::query_selector_allwere moved toIParentNode - (breaking change)
Document::get_element_by_idwas moved toINonElementParentNode - (breaking change) A blanket impl for converting between arbitrary reference-like objects using
TryFrom/TryIntohas been removed - When building using a recent
cargo-webit's not necessary to callstdweb::initializenorstdweb::event_loopanymore - Support for
cdylibcrates onwasm32-unknown-unknown - New bindings:
XmlHttpRequestWebSocketMutationObserverHistoryTextAreaElementCanvasElement
- New event types:
MouseDownEventMouseUpEventMouseMoveEventPopStateEventResizeEventReadyStateChangeSocketCloseEventSocketErrorEventSocketOpenEventSocketMessageEvent
- Initial support for the Canvas APIs
- New traits:
ReferenceTypeandInstanceOf - Add
#[derive(ReferenceType)]instdweb-derivecrate; it's now possible to define custom API bindings outside ofstdweb - Add
#[js_export]procedural attribute (wasm32-unknown-unknownonly) - Add
DomExceptionand subtypes for passing around JavaScript exceptions IElementnow inherits fromINode- Every interface now inherits from
ReferenceType - Add
stdweb::traitsmodule to act as a prelude foruse-ing all of our interface traits - Add
console!macro - Most types now implement
PartialEqandEq
- (breaking change) Removed
-
0.3- (breaking change) Deleted
ErrorEventmethods - (breaking change) Renamed:
LoadEvent->ResourceLoadEventAbortEvent->ResourceAbortEventErrorEvent->ResourceErrorEvent
- Add
UnsafeTypedArrayfor zero cost slice passing tojs! - Add
Oncefor passingFnOnceclosures tojs!
- (breaking change) Deleted
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.
See CONTRIBUTING.md

