1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
#![deny(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
//! 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](https://github.com/matklad/cargo-xtask/), instead of using
//! external tooling like [`wasm-pack`](https://github.com/rustwasm/wasm-pack).
//!
//! # Minimum Supported Rust Version
//!
//! This crate requires **Rust 1.58.1** at a minimum because there is a security
//! issue on a function we use from std in previous version
//! (see [cve-2022-21658](https://groups.google.com/g/rustlang-security-announcements/c/R1fZFDhnJVQ)).
//!
//! # 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`:
//!
//! ```console
//! mkdir my-project
//! cd my-project
//! touch Cargo.toml
//! ```
//!
//! * Create the project package and the xtask package using `cargo new`:
//!
//! ```console
//! cargo new my-project
//! cargo new xtask
//! ```
//!
//! * Open the workspace's `Cargo.toml` and add the following:
//!
//! ```toml
//! [workspace]
//! default-members = ["my-project"]
//! members = [
//! "my-project",
//! "xtask",
//! ]
//! ```
//!
//! * Create a `.cargo/config.toml` file and add the following content:
//!
//! ```toml
//! [alias]
//! xtask = "run --package xtask --"
//! ```
//!
//! The directory layout should look like this:
//!
//! ```console
//! project
//! ├── .cargo
//! │ └── config.toml
//! ├── Cargo.toml
//! ├── my-project
//! │ ├── Cargo.toml
//! │ └── src
//! │ └── ...
//! └── xtask
//! ├── Cargo.toml
//! └── src
//! └── main.rs
//! ```
//!
//! And now you can run your xtask package using:
//!
//! ```console
//! cargo xtask
//! ```
//!
//! You can find more informations about xtask
//! [here](https://github.com/matklad/cargo-xtask/).
//!
//! ## Use xtask-wasm as a dependency
//!
//! Finally, add the following to the xtask package's `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! xtask-wasm = "0.1.0"
//! ```
//!
//! # Usage
//!
//! This library gives you three structs:
//!
//! * [`Dist`](crate::dist::Dist) - Generate a distributed package for Wasm.
//! * [`Watch`](https://docs.rs/xtask-watch/latest/xtask_watch/struct.Watch.html) -
//! Re-run a given command when changes are detected
//! (using [xtask-watch](https://github.com/rustminded/xtask-watch)).
//! * [`DevServer`](crate::dev_server::DevServer) - Serve your project at a given IP address.
//!
//! They all implement [`clap::Parser`](https://docs.rs/clap/latest/clap/trait.Parser.html)
//! allowing them to be added easily to an existing CLI implementation and are
//! flexible enough to be customized for most use-cases.
//!
//! You can find further information for each type at their documentation level.
//!
//! # Examples
//!
//! ## A basic implementation
//!
//! ```rust,no_run
//! use std::process::Command;
//! use xtask_wasm::{anyhow::Result, clap, default_dist_dir};
//!
//! #[derive(clap::Parser)]
//! enum Opt {
//! Dist(xtask_wasm::Dist),
//! Watch(xtask_wasm::Watch),
//! Start(xtask_wasm::DevServer),
//! }
//!
//!
//! fn main() -> Result<()> {
//! let opt: Opt = clap::Parser::parse();
//!
//! match opt {
//! Opt::Dist(dist) => {
//! log::info!("Generating package...");
//!
//! dist
//! .dist_dir_path("dist")
//! .static_dir_path("my-project/static")
//! .app_name("my-project")
//! .run_in_workspace(true)
//! .run("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(mut dev_server) => {
//! log::info!("Starting the development server...");
//!
//! dev_server.arg("dist").start(default_dist_dir(false))?;
//! }
//! }
//!
//! Ok(())
//! }
//! ```
//!
//! ## [`examples/demo`](https://github.com/rustminded/xtask-wasm/tree/main/examples/demo)
//!
//! Provides a basic implementation of xtask-wasm to generate the web app
//! package, an "hello world" app using [Yew](https://yew.rs/). This example
//! demonstrates a simple directory layout and a customized dist process
//! that use the `wasm-opt` feature.
//!
//! The available subcommands are:
//!
//! * Build the web app package.
//!
//! ```console
//! cargo xtask dist
//! ```
//! * Build the web app package, download the [`wasm-opt`](https://github.com/WebAssembly/binaryen#tools)
//! binary and optimize the Wasm generated by the dist process.
//!
//! ```console
//! cargo xtask dist --optimize
//! ```
//!
//! * Build the web app package and watch for changes in the workspace root.
//!
//! ```console
//! cargo xtask watch
//! ```
//!
//! * Serve an optimized web app dist on `127.0.0.1:8000` and watch for
//! changes in the workspace root.
//!
//! ```console
//! 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:
//!
//! ```console
//! cargo run --example run_example
//! ```
//!
//! This command will run the code in `examples/run_example` using the development server.
//!
//! # Features
//!
//! * `wasm-opt`: enable the [`WasmOpt`](crate::wasm_opt::WasmOpt) struct that helps downloading
//! and using [`wasm-opt`](https://github.com/WebAssembly/binaryen#tools) very easily.
//! * `run-example`: a helper to run examples from `examples/` directory using a development
//! server.
//! * `sass`: allow the use of SASS/SCSS in your project.
//!
//! # Troubleshooting
//!
//! When using the re-export of [`clap`](https://docs.rs/clap/latest/clap), you
//! might encounter this error:
//!
//! ```console
//! 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:
//!
//! ```rust
//! use xtask_wasm::clap;
//!
//! #[derive(clap::Parser)]
//! struct MyStruct {}
//! ```
//!
//! Or like this:
//!
//! ```rust
//! use xtask_wasm::{clap, clap::Parser};
//!
//! #[derive(Parser)]
//! struct MyStruct {}
//! ```
#[macro_use]
mod cfg;
cfg_not_wasm32! {
use std::process::Command;
pub use xtask_watch::{
anyhow, cargo_metadata, cargo_metadata::camino, clap, metadata, package, xtask_command,
Watch,
};
mod dev_server;
mod dist;
pub use dev_server::*;
pub use dist::*;
cfg_run_example! {
pub use env_logger;
pub use log;
}
cfg_wasm_opt! {
mod wasm_opt;
pub use wasm_opt::*;
}
cfg_sass! {
pub use sass_rs;
}
/// Get the default command for the build in the dist process.
///
/// This is `cargo build --target wasm32-unknown-unknown`.
pub fn default_build_command() -> Command {
let mut command = Command::new("cargo");
command.args(["build", "--target", "wasm32-unknown-unknown"]);
command
}
}
cfg_wasm32! {
cfg_run_example! {
pub use console_error_panic_hook;
pub use wasm_bindgen;
}
}
cfg_run_example! {
pub use xtask_wasm_run_example::*;
}