This cargo subcommand aims to make it easy and convenient to build, develop and deploy client-side Web applications written in Rust.
This software was brought to you thanks to these wonderful people:
Thank you!
Currently it supports the following features:
cargo web build
- will build your project using one of Rust's three Web backends:
--target=wasm32-unknown-unknown
; default)--target=wasm32-unknown-emscripten
)--target=asmjs-unknown-emscripten
)cargo web check
- will typecheck your projectcargo web test
- will run your tests either under:
--nodejs
)cargo web start
- will build your project, start an embedded webserver and will continuously
rebuild it if necessary; supports automatic reloading with --auto-reload
.cargo web deploy
- will build your project and emit all of the necessary files so that
you can easily serve them statically.rustup
It's also highly recommended that you check out the stdweb crate if you want
to interact with the JavaScript world in your project. (In fact, cargo-web
is what makes it possible to use stdweb
's js!
macro on Rust's native WebAssembly
backend.)
$ cargo install cargo-web
To upgrade:
$ cargo install --force cargo-web
Or clone and build with $ cargo build --release
then place in your $PATH.
On Linux the installation can fail with a message that it can't find OpenSSL,
in which case you most likely need to install the -dev
package for OpenSSL
from your distribution's repositories. (On Ubuntu it's called libssl-dev
.)
Web.toml
cargo-web
has its own configuration file which you can put next to cargo
's Cargo.toml
.
Here's an example configuration showing every supported key:
# The default value of `--target` used when building this crate
# in cases where it's not specified on the command line.
default-target = "wasm32-unknown-unknown"
# This will prepend a given JavaScript file to the resulting `.js` artifact.
# You can put any initialization code here which you'd like to have executed
# when your `.js` file first loads.
#
# This accepts either a string (as shown here), or an array of strings,
# in which case it will prepend all of the specified files in their
# order of appearance.
prepend-js = "src/runtime.js"
[cargo-web]
# Asserts the minimum required version of `cargo-web` necessary
# to compile this crate; supported since 0.6.0.
minimum-version = "0.6.0"
# These will only take effect on *-emscripten targets.
[target.emscripten]
# You can have a target-specific `prepend-js` key.
prepend-js = "src/emscripten_runtime.js"
# This will enable Emscripten's SDL2 port. Consult Emscripten's documentation
# for more details.
link-args = ["-s", "USE_SDL=2"]
# You can also specify the target by its full name.
[target.wasm32-unknown-unknown]
prepend-js = "src/native_runtime.js"
If you use any external crates which have a Web.toml
then cargo-web
will load it and use it.
A few restrictions concerning the Web.toml
:
prepend-js
keys. You can either define
a single global prepend-js
, or multiple per-target ones.link-args
currently can't have any spaces in them.cargo-web
will process the Web.toml
files
from multiple crates is deterministic yet unspecified. This means
that you shouldn't depend on this order in any way.Any static files you'd like to have served when running cargo web start
or deployed
when running cargo web deploy
can be put in a directory called static
in the root
of your crate. No static artifacts are required by default; an index.html
file will
be automatically generated for you if it's missing. You can, of course, put your own static/index.html
file, in which case it will be used instead of the autogenerated one.
cargo-web
during compilationIf during compilation you'd like to detect that your project is being built with cargo-web
you can check the COMPILING_UNDER_CARGO_WEB
environment variable, which will be set to 1
.
cargo-web
on TravisYou can use the following script to download and install the latest cargo-web
:
CARGO_WEB_RELEASE=$(curl -L -s -H 'Accept: application/json' https://github.com/koute/cargo-web/releases/latest)
CARGO_WEB_VERSION=$(echo $CARGO_WEB_RELEASE | sed -e 's/.*"tag_name":"\([^"]*\)".*/\1/')
if [ "$(uname -s)" == "Darwin" ]; then
CARGO_WEB_HOST_TRIPLE="x86_64-apple-darwin"
else
CARGO_WEB_HOST_TRIPLE="x86_64-unknown-linux-gnu"
fi
CARGO_WEB_URL="https://github.com/koute/cargo-web/releases/download/$CARGO_WEB_VERSION/cargo-web-$CARGO_WEB_HOST_TRIPLE.gz"
echo "Downloading cargo-web from: $CARGO_WEB_URL"
curl -L $CARGO_WEB_URL | gzip -d > cargo-web
chmod +x cargo-web
mkdir -p ~/.cargo/bin
mv cargo-web ~/.cargo/bin
By default cargo web test
will run your tests under headless Chrome. To be able to use this on Travis
you need to add something like this to your .travis.yml
:
addons:
chrome: stable
wasm32-unknown-unknown
-only)When building a project by default cargo-web
generates a standalone runtime
runtime for you. What this means is that the .js
file which is generated
can be immediately put inside of a <script>
tag or launched with Node.js
without having to load it manually or do anything extra, however this does
limit you when it comes to customizability.
If you'd like to have a little more control on how your module is loaded
then you can tell cargo-web
to generate a non-standalone, library-like
module for you with the --runtime library-es6
option. This will result
in a .js
file which exports a factory function with the following interface:
export default function() {
return {
imports: { ... },
initialize: function( instance ) { ... }
};
}
Here you have to instantiate the WebAssembly module yourself; in this
case you have to pass imports
as its imports, and then immediately
after instantiating it call initialize
.
For example, assuming you'll name your module generated by the cargo-web
as my-module.mjs
and my-module.wasm
you can instantiate it like this from Node.js:
import fs from "fs";
import factory from "my-module.mjs";
// We read in the `.wasm` module.
const bytecode = fs.readFileSync( "my-module.wasm" );
const wasm = new WebAssembly.Module( bytecode );
// We instantiate it.
const instance = factory();
const compiled = new WebAssembly.Instance( wasm, instance.imports );
// This will initialize the module and call your `main`, if you have one.
const exports = instance.initialize( compiled );
// In the object it returns you can find any functions which
// you've exported with `stdweb`'s `#[js_export]` macro.
console.log( exports.add( 1, 2 ) );
Then you can run it with node --experimental-modules run.mjs
.
This is useful if you want to load your .wasm
file from a custom URL or
you want to integrate the output with a JavaScript bundler, or anything
else which requires you to load the module yourself.
0.6.26
--no-default-features
flag was fixedmime-guess
crate is now being used to guess the mime types by the embedded webserver0.6.25
cargo web start
will now try to not trigger superfluous rebuilds when the project's
files are modified in quick succession0.6.24
[target.'cfg(...)'.dependencies]
are now properly supportedcfg(cargo_web)
to detect whenever your crate is being compiled under cargo-web
target/wasm32-unknown-unknown/*/deps/*.wasm
are now ignored; this should prevent
cargo-web
from processing superfluous .wasm
artifacts generated due to dependencies also being cdylib
scargo-web
is now available as a library through a structopt
-based interface0.6.23
cargo web check
wasm32-unknown-unknown
target is now the default0.6.22
deploy
subcommand can now be told where to deploy using the -o
/--output
parameterAccess-Control-Allow-Origin: *
is now always sent by the embedded webserverwasm32-unknown-unknown
are now supported provided a recent enough stdweb
is used0.6.21
1.38.19
; the Emscripten-based targets should now work again on nightlywasm32-unknown-unknown
are now sortedwasm32-unknown-unknown
0.6.20
cargo install
should now work againdeploy
should not panic when it doesn't find a valid target0.6.19
cargo install
should now compile instead of failing in some environments1.26.2
0.6.18
index.html
doesn't have a newline before its doctype anymore0.6.17
1.25.0
0.6.16
wasm32-unknown-unknown
now uses WebAssembly.instantiateStreaming
when availablewasm32-unknown-unknown
targetcargo-web
is redirectedLicensed under either of
at your option.
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.