guide/src/reference/js-snippets.md
Often when developing a crate you want to run on the web you'll want to include
some JS code here and there. While js-sys and
web-sys cover many needs they don't cover
everything, so wasm-bindgen supports the ability to write JS code next to your
Rust code and have it included in the final output artifact.
To include a local JS file, you'll use the #[wasm_bindgen(module)] macro:
#[wasm_bindgen(module = "/js/foo.js")]
extern "C" {
fn add(a: u32, b: u32) -> u32;
}
This declaration indicates that all the functions contained in the extern
block are imported from the file /js/foo.js, where the root is relative to the
crate root (where Cargo.toml is located).
The /js/foo.js file will make its way to the final output when wasm-bindgen
executes, so you can use the module annotation in a library without having to
worry users of your library!
The JS file itself must be written with ES module syntax:
export function add(a, b) {
return a + b;
}
A full design of this feature can be found in RFC 6 as well if you're interested!
inline_jsIn addition to module = "..." if you're a macro author you also have the
ability to use the inline_js attribute:
#[wasm_bindgen(inline_js = "export function add(a, b) { return a + b; }")]
extern "C" {
fn add(a: u32, b: u32) -> u32;
}
Using inline_js indicates that the JS module is specified inline in the
attribute itself, and no files are loaded from the filesystem. They have the
same limitations and caveats as when using module, but can sometimes be easier
to generate for macros themselves. It's not recommended for hand-written code to
make use of inline_js but instead to leverage module where possible.
While quite useful local JS snippets currently suffer from a few caveats which are important to be aware of. Many of these are temporary though!
Currently import statements are not supported in the JS file. This is a
restriction we may lift in the future once we settle on a good way to support
this. For now, though, js snippets must be standalone modules and can't import
from anything else.
Only --target web and the default bundler output mode are supported. To
support --target nodejs we'd need to translate ES module syntax to CommonJS
(this is
planned to be done, just hasn't been done yet). Additionally to support
--target no-modules we'd have to similarly translate from ES modules to
something else.
Paths in module = "..." must currently start with /, or be rooted at the
crate root. It is intended to eventually support relative paths like ./ and
../, but it's currently believed that this requires more support in
the Rust proc_macro crate.
As above, more detail about caveats can be found in RFC 6.