Compiling Rust to WebAssembly is still difficult. On macOS, there are weird bugs that require reinstalling LLVM and moving files around. On Linux, the official Emscripten binary in many cases isn’t bundled with the right LLVM, and the fix is to compile from scratch, a multi-hour process. In Travis CI, the standard “solution” is to install an Alpine Linux chroot to get the latest Emscripten. It’s a clever workaround, but shouldn’t there be a better way?
wargo
is a drop in wrapper for cargo
that automatically installs and configures Emscripten for you (on macOS or Linux), avoiding or autofixing all of the above bugs. It can also automatically run your tests in a real web browser using WebDriver! The source code is on GitHub. To install, use npm with Node 6 or newer:1
npm install -g wargo
Let’s compile our first WebAssembly project! With wargo
, it’s pretty simple:
cargo new --bin meow
cd meow
wargo build
With just a single command, wargo
downloads the appropriate Emscripten binary, checks for dependencies, configures environment variables, and runs cargo build
. You can find your freshly compiled wasm
files in the target/wasm32-unknown-emscripten
directory.
Testing Locally
Another command, wargo test
, automatically uses WebDriver to test your WebAssembly code. If you’ve got chromedriver
installed (on macOS, brew install chromedriver
) you can run this to start the WebDriver server:
chromedriver --port=4445 --url-base=/wd/hub
Once the server is up and running2 on port 4445, you can run
wargo test
in your project. We’ll automatically build a test binary and run it with WebDriver. This lets you write tests just like you would any other Rust project! Console output from the browser appears in your terminal:
$ wargo test
Setup wasm checking dependencies...
Setup wasm found emsdk installation in ~/.emsdk
Setup wasm setting environment...
(...)
Setup wasm running 'cargo test --target=wasm32-unknown-emscripten --no-run --message-format=json'
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Setup wasm running tests...
pre-main prep time: 566 ms
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Testing in Travis
With a free-for-open-source Sauce Labs account, you can easily test your WebAssembly project in Travis CI, even with multiple browsers! Just put this in your .travis.yml
:
language: rust
rust: stable
install:
- npm install -g wargo
# install recent cmake, since Trusty only ships with an old version
- (cd ~; curl -sSL https://cmake.org/files/v3.5/cmake-3.5.2-Linux-x86_64.tar.gz | tar -xz)
- sudo mv /usr/bin/cmake /usr/bin/cmake.old
- sudo ln -s ~/cmake-3.5.2-Linux-x86_64/bin/cmake /usr/bin/cmake
script:
- wargo build --verbose
- wargo test --verbose
addons:
sauce_connect:
username: "TODO your Sauce Labs username"
access_key: "TODO your Sauce Labs access key"
If you want to test in a different type of browser, you can put Sauce Labs configuration JSON in the WEBDRIVER_CAPABILITIES
environment variable. For instance, you could add this line under install:
to test in Chrome 60 running on Windows 8:
- export WEBDRIVER_CAPABILITIES='{"browserName": "chrome", "platform": "Windows 8", "version": "60.0"}'
Using with Webpack
There is also the wargo-loader
package for use with Webpack, based off rust-emscripten-loader by Matt Dziuban.
cargo new --bin meow
cd meow
We’ll create a package.json
file with the autowasm dependency and some helper scripts:
echo '{
"devDependencies": {
"http-server": "^0.10.0",
"wargo-loader": "^0.3.0",
"webpack": "^3.7.1"
},
"scripts": {
"compile": "webpack --progress",
"serve": "http-server"
}
}' > package.json
We’ll next create a index.js
file to load in the WebAssembly, as well as a simple index.html
file and a Webpack config file.
echo '
const wasm = require("./main.rs")
wasm.initialize({noExitRuntime: true}).then(module => {
// you can call module.cwrap here to get function wrappers for Rust functions
})
' > src/index.js
echo '<!DOCTYPE html> <script src="build/bundle.js"></script>' > index.html
curl -L https://git.io/vdNTe > webpack.config.js
With all the files in place, we just need to install the dependencies, run webpack with the compile
script, and start the server.
npm install
npm run compile
npm run serve
If you open localhost:8080, you’ll just see a blank screen. But open up the JavaScript console, and you should see your “Hello, World!” from Rust!
Please Help Bugtest!
There will be bugs. It works on all the computers I’ve tested, and in Travis, but I can only test so many environments. If you’re on macOS or Linux and can’t run wargo build
on a freshly created cargo new --bin meow
, that’s a bug, and I’d love a bug report if you have the time! If we can solve your bug, we can automate it away so nobody has to deal with it again.
-
The original version was written in Rust, but the multiple-minute compile times got a bit annoying, especially in CI. And if you’re writing WebAssembly, you probably have Node installed already. ↩
-
If you’re running WebDriver on a different port or host, you can customize where wargo looks with the
WEBDRIVER_HOST
andWEBDRIVER_PORT
environment variables. ↩