Expand description
This crate aims to provide an easy and customizable way to help you build
Wasm projects by extending them with custom subcommands, based on the
xtask concept, instead of using
external tooling like wasm-pack.
§Why xtask-wasm?
§No external tools to install
wasm-pack and trunk are separate binaries that must be installed outside
of Cargo — via cargo install, a shell script, or a system package manager.
This means every contributor and every CI machine needs an extra installation
step, and there is no built-in guarantee that everyone is running the same
version.
With xtask-wasm, cargo xtask is all you need. The build tooling is a
regular Cargo dependency, versioned in your Cargo.lock and reproduced
exactly like every other dependency in your project.
§wasm-bindgen version is always in sync
This is the most common source of pain with wasm-pack and trunk: the
wasm-bindgen CLI tool version must exactly match the wasm-bindgen library
version declared in your Cargo.toml. When they drift — after a cargo update, a fresh clone, or a CI cache invalidation — you get a cryptic error
at runtime rather than a clear compile-time failure.
xtask-wasm uses wasm-bindgen-cli-support
as a library dependency. The version is pinned in your Cargo.lock alongside
your wasm-bindgen library dependency and kept in sync automatically — no
manual version matching required.
§Fully customizable
Because the build process is plain Rust code living inside your workspace,
you can extend, replace or wrap any step. wasm-pack and trunk are
opaque binaries driven by configuration files; xtask-wasm gives you the full
build logic as code, under your control.
§Setup
The best way to add xtask-wasm to your project is to create a workspace with two packages: your project’s package and the xtask package.
§Create a project using xtask
-
Create a new directory that will contains the two package of your project and the workspace’s
Cargo.toml:mkdir my-project cd my-project touch Cargo.toml -
Create the project package and the xtask package using
cargo new:cargo new my-project cargo new xtask -
Open the workspace’s
Cargo.tomland add the following:[workspace] default-members = ["my-project"] members = [ "my-project", "xtask", ] resolver = "2" -
Create a
.cargo/config.tomlfile and add the following content:[alias] xtask = "run --package xtask --"
The directory layout should look like this:
project
├── .cargo
│ └── config.toml
├── Cargo.toml
├── my-project
│ ├── Cargo.toml
│ └── src
│ └── ...
└── xtask
├── Cargo.toml
└── src
└── main.rsAnd now you can run your xtask package using:
cargo xtaskYou can find more informations about xtask here.
§Use xtask-wasm as a dependency
Finally, add xtask-wasm to your dependencies:
cargo add -p xtask xtask-wasm§Usage
This library gives you three structs:
Dist- Generate a distributed package for Wasm.Watch- Re-run a given command when changes are detected (using xtask-watch).DevServer- Serve your project at a given IP address.
They all implement clap::Parser
allowing them to be added easily to an existing CLI implementation and are
flexible enough to be customized for most use-cases.
The pre and post hooks of DevServer
accept any type implementing the
Hook trait.
This lets you construct a std::process::Command based on the server’s final configuration
— for example, to pass the resolved dist_dir or port as arguments to an external tool.
A blanket implementation is provided for std::process::Command itself, so no changes are
needed for simple use-cases.
Asset files copied by Dist
can be processed by types implementing the
Transformer trait.
Transformers are tried in order for each file; the first to return Ok(true) claims the file,
while unclaimed files are copied verbatim. When the sass feature is enabled,
SassTransformer
is available to compile SASS/SCSS files to CSS.
You can find further information for each type at their documentation level.
§Examples
§A basic implementation
use std::process::Command;
use xtask_wasm::{anyhow::Result, clap};
#[derive(clap::Parser)]
enum Opt {
Dist(xtask_wasm::Dist),
Watch(xtask_wasm::Watch),
Start(xtask_wasm::DevServer),
}
fn main() -> Result<()> {
env_logger::builder()
.filter_level(log::LevelFilter::Info)
.init();
let opt: Opt = clap::Parser::parse();
match opt {
Opt::Dist(dist) => {
log::info!("Generating package...");
dist
.assets_dir("my-project/assets")
.app_name("my-project")
.build("my-project")?;
}
Opt::Watch(watch) => {
log::info!("Watching for changes and check...");
let mut command = Command::new("cargo");
command.arg("check");
watch.run(command)?;
}
Opt::Start(dev_server) => {
log::info!("Starting the development server...");
dev_server
.xtask("dist")
.start()?;
}
}
Ok(())
}Note: this basic implementation uses env_logger and log. Add them to the Cargo.toml of
your xtask (or use your preferred logger).
§examples/demo
Provides a basic implementation of xtask-wasm to generate the web app
package, an “hello world” app using Yew. This example
demonstrates a simple directory layout and a dist process that uses the
wasm-opt feature via Dist::optimize_wasm.
The available subcommands are:
-
Build and optimize the web app package (downloads
wasm-optif not cached).cargo xtask dist -
Build the web app package and watch for changes in the workspace root.
cargo xtask watch -
Serve an optimized web app dist on
127.0.0.1:8000and watch for changes in the workspace root.cargo xtask start
Additional flags can be found using cargo xtask <subcommand> --help.
This example also demonstrates the use of the run-example feature that allows you to use the
following:
cargo run --example run_exampleThis command will run the code in examples/run_example using the development server.
§Features
-
wasm-opt: enable theWasmOptstruct andDist::optimize_wasmfor downloading and runningwasm-optautomatically as part of the dist build. This is the recommended way to integrate wasm-opt — no custom wrapper struct or manual path computation needed:ⓘ// requires the `wasm-opt` feature dist.optimize_wasm(WasmOpt::level(1).shrink(2)) .build("my-project")?; -
run-example: a helper to run examples fromexamples/directory using a development server. -
sass: enable SASS/SCSS compilation viaSassTransformer. Add it to yourDistwith.transformer(SassTransformer::default()).
§Troubleshooting
When using the re-export of clap, you
might encounter this error:
error[E0433]: failed to resolve: use of undeclared crate or module `clap`
--> xtask/src/main.rs:4:10
|
4 | #[derive(Parser)]
| ^^^^^^ use of undeclared crate or module `clap`
|
= note: this error originates in the derive macro `Parser` (in Nightly builds, run with -Z macro-backtrace for more info)This occurs because you need to import clap in the scope too. This error can be resolved like this:
use xtask_wasm::clap;
#[derive(clap::Parser)]
struct MyStruct {}Or like this:
use xtask_wasm::{clap, clap::Parser};
#[derive(Parser)]
struct MyStruct {}Re-exports§
pub use xtask_watch::anyhow;Non-WebAssembly pub use xtask_watch::cargo_metadata;Non-WebAssembly pub use xtask_watch::cargo_metadata::camino;Non-WebAssembly pub use xtask_watch::clap;Non-WebAssembly pub use sass_rs;sasspub use env_logger;run-examplepub use log;run-example
Structs§
- DevServer
Non-WebAssembly - A simple HTTP server useful during development.
- Dist
Non-WebAssembly - A helper to generate the distributed package.
- Request
Non-WebAssembly - Abstraction over an HTTP request.
- Sass
Transformer sass - A
Transformerthat compiles SASS/SCSS files to CSS. - WasmOpt
wasm-opt - Helper Abstracting the
wasm-optbinary from binaryen for easily optimizing your Wasm binary. - Watch
Non-WebAssembly - Watches over your project’s source code, relaunching a given command when changes are detected.
Traits§
- Hook
Non-WebAssembly - A type that can produce a
process::Commandgiven the finalDevServerconfiguration. - Transformer
Non-WebAssembly - A type that can transform or copy a single asset file during
Dist::build.
Functions§
- default_
build_ command Non-WebAssembly - Get the default command for the build in the dist process.
- default_
request_ handler Non-WebAssembly - Default request handler
- metadata
Non-WebAssembly - Fetch the metadata of the crate.
- package
Non-WebAssembly - Fetch information of a package in the current crate.
- xtask_
command Non-WebAssembly - Return a
std::process::Commandof the xtask command currently running.
Attribute Macros§
- run_
example run-example - This macro helps to run an example in the project’s
examples/directory using a development server.